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:
Коммит
a66d2c8f7e
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
|
|
14
fs/afs/dir.c
14
fs/afs/dir.c
|
@ -20,16 +20,16 @@
|
|||
#include "internal.h"
|
||||
|
||||
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd);
|
||||
unsigned int flags);
|
||||
static int afs_dir_open(struct inode *inode, struct file *file);
|
||||
static int afs_readdir(struct file *file, void *dirent, filldir_t filldir);
|
||||
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd);
|
||||
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags);
|
||||
static int afs_d_delete(const struct dentry *dentry);
|
||||
static void afs_d_release(struct dentry *dentry);
|
||||
static int afs_lookup_filldir(void *_cookie, const char *name, int nlen,
|
||||
loff_t fpos, u64 ino, unsigned dtype);
|
||||
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd);
|
||||
bool excl);
|
||||
static int afs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode);
|
||||
static int afs_rmdir(struct inode *dir, struct dentry *dentry);
|
||||
static int afs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
|
@ -516,7 +516,7 @@ out:
|
|||
* look up an entry in a directory
|
||||
*/
|
||||
static struct dentry *afs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct afs_vnode *vnode;
|
||||
struct afs_fid fid;
|
||||
|
@ -598,7 +598,7 @@ success:
|
|||
* - NOTE! the hit can be a negative hit too, so we can't assume we have an
|
||||
* inode
|
||||
*/
|
||||
static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
static int afs_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct afs_vnode *vnode, *dir;
|
||||
struct afs_fid uninitialized_var(fid);
|
||||
|
@ -607,7 +607,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
void *dir_version;
|
||||
int ret;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
vnode = AFS_FS_I(dentry->d_inode);
|
||||
|
@ -949,7 +949,7 @@ error:
|
|||
* create a regular file on an AFS filesystem
|
||||
*/
|
||||
static int afs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
struct afs_file_status status;
|
||||
struct afs_callback cb;
|
||||
|
|
|
@ -22,7 +22,7 @@
|
|||
|
||||
static struct dentry *afs_mntpt_lookup(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
struct nameidata *nd);
|
||||
unsigned int flags);
|
||||
static int afs_mntpt_open(struct inode *inode, struct file *file);
|
||||
static void afs_mntpt_expiry_timed_out(struct work_struct *work);
|
||||
|
||||
|
@ -104,7 +104,7 @@ out:
|
|||
*/
|
||||
static struct dentry *afs_mntpt_lookup(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
_enter("%p,%p{%p{%s},%s}",
|
||||
dir,
|
||||
|
|
|
@ -395,7 +395,7 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
|
|||
as->volume = vol;
|
||||
|
||||
/* allocate a deviceless superblock */
|
||||
sb = sget(fs_type, afs_test_super, afs_set_super, as);
|
||||
sb = sget(fs_type, afs_test_super, afs_set_super, flags, as);
|
||||
if (IS_ERR(sb)) {
|
||||
ret = PTR_ERR(sb);
|
||||
afs_put_volume(vol);
|
||||
|
@ -406,7 +406,6 @@ static struct dentry *afs_mount(struct file_system_type *fs_type,
|
|||
if (!sb->s_root) {
|
||||
/* initial superblock/root creation */
|
||||
_debug("create");
|
||||
sb->s_flags = flags;
|
||||
ret = afs_fill_super(sb, ¶ms);
|
||||
if (ret < 0) {
|
||||
deactivate_locked_super(sb);
|
||||
|
|
73
fs/aio.c
73
fs/aio.c
|
@ -56,13 +56,6 @@ static struct kmem_cache *kioctx_cachep;
|
|||
|
||||
static struct workqueue_struct *aio_wq;
|
||||
|
||||
/* Used for rare fput completion. */
|
||||
static void aio_fput_routine(struct work_struct *);
|
||||
static DECLARE_WORK(fput_work, aio_fput_routine);
|
||||
|
||||
static DEFINE_SPINLOCK(fput_lock);
|
||||
static LIST_HEAD(fput_head);
|
||||
|
||||
static void aio_kick_handler(struct work_struct *);
|
||||
static void aio_queue_work(struct kioctx *);
|
||||
|
||||
|
@ -479,7 +472,6 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
|
|||
{
|
||||
unsigned short allocated, to_alloc;
|
||||
long avail;
|
||||
bool called_fput = false;
|
||||
struct kiocb *req, *n;
|
||||
struct aio_ring *ring;
|
||||
|
||||
|
@ -495,28 +487,11 @@ static int kiocb_batch_refill(struct kioctx *ctx, struct kiocb_batch *batch)
|
|||
if (allocated == 0)
|
||||
goto out;
|
||||
|
||||
retry:
|
||||
spin_lock_irq(&ctx->ctx_lock);
|
||||
ring = kmap_atomic(ctx->ring_info.ring_pages[0]);
|
||||
|
||||
avail = aio_ring_avail(&ctx->ring_info, ring) - ctx->reqs_active;
|
||||
BUG_ON(avail < 0);
|
||||
if (avail == 0 && !called_fput) {
|
||||
/*
|
||||
* Handle a potential starvation case. It is possible that
|
||||
* we hold the last reference on a struct file, causing us
|
||||
* to delay the final fput to non-irq context. In this case,
|
||||
* ctx->reqs_active is artificially high. Calling the fput
|
||||
* routine here may free up a slot in the event completion
|
||||
* ring, allowing this allocation to succeed.
|
||||
*/
|
||||
kunmap_atomic(ring);
|
||||
spin_unlock_irq(&ctx->ctx_lock);
|
||||
aio_fput_routine(NULL);
|
||||
called_fput = true;
|
||||
goto retry;
|
||||
}
|
||||
|
||||
if (avail < allocated) {
|
||||
/* Trim back the number of requests. */
|
||||
list_for_each_entry_safe(req, n, &batch->head, ki_batch) {
|
||||
|
@ -570,36 +545,6 @@ static inline void really_put_req(struct kioctx *ctx, struct kiocb *req)
|
|||
wake_up_all(&ctx->wait);
|
||||
}
|
||||
|
||||
static void aio_fput_routine(struct work_struct *data)
|
||||
{
|
||||
spin_lock_irq(&fput_lock);
|
||||
while (likely(!list_empty(&fput_head))) {
|
||||
struct kiocb *req = list_kiocb(fput_head.next);
|
||||
struct kioctx *ctx = req->ki_ctx;
|
||||
|
||||
list_del(&req->ki_list);
|
||||
spin_unlock_irq(&fput_lock);
|
||||
|
||||
/* Complete the fput(s) */
|
||||
if (req->ki_filp != NULL)
|
||||
fput(req->ki_filp);
|
||||
|
||||
/* Link the iocb into the context's free list */
|
||||
rcu_read_lock();
|
||||
spin_lock_irq(&ctx->ctx_lock);
|
||||
really_put_req(ctx, req);
|
||||
/*
|
||||
* at that point ctx might've been killed, but actual
|
||||
* freeing is RCU'd
|
||||
*/
|
||||
spin_unlock_irq(&ctx->ctx_lock);
|
||||
rcu_read_unlock();
|
||||
|
||||
spin_lock_irq(&fput_lock);
|
||||
}
|
||||
spin_unlock_irq(&fput_lock);
|
||||
}
|
||||
|
||||
/* __aio_put_req
|
||||
* Returns true if this put was the last user of the request.
|
||||
*/
|
||||
|
@ -618,21 +563,9 @@ static int __aio_put_req(struct kioctx *ctx, struct kiocb *req)
|
|||
req->ki_cancel = NULL;
|
||||
req->ki_retry = NULL;
|
||||
|
||||
/*
|
||||
* Try to optimize the aio and eventfd file* puts, by avoiding to
|
||||
* schedule work in case it is not final fput() time. In normal cases,
|
||||
* we would not be holding the last reference to the file*, so
|
||||
* this function will be executed w/out any aio kthread wakeup.
|
||||
*/
|
||||
if (unlikely(!fput_atomic(req->ki_filp))) {
|
||||
spin_lock(&fput_lock);
|
||||
list_add(&req->ki_list, &fput_head);
|
||||
spin_unlock(&fput_lock);
|
||||
schedule_work(&fput_work);
|
||||
} else {
|
||||
req->ki_filp = NULL;
|
||||
really_put_req(ctx, req);
|
||||
}
|
||||
fput(req->ki_filp);
|
||||
req->ki_filp = NULL;
|
||||
really_put_req(ctx, req);
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
|
|
@ -171,6 +171,8 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
|
|||
struct timespec now;
|
||||
unsigned int ia_valid = attr->ia_valid;
|
||||
|
||||
WARN_ON_ONCE(!mutex_is_locked(&inode->i_mutex));
|
||||
|
||||
if (ia_valid & (ATTR_MODE | ATTR_UID | ATTR_GID | ATTR_TIMES_SET)) {
|
||||
if (IS_IMMUTABLE(inode) || IS_APPEND(inode))
|
||||
return -EPERM;
|
||||
|
@ -250,5 +252,4 @@ int notify_change(struct dentry * dentry, struct iattr * attr)
|
|||
|
||||
return error;
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(notify_change);
|
||||
|
|
|
@ -257,8 +257,8 @@ static int autofs_dev_ioctl_open_mountpoint(const char *name, dev_t devid)
|
|||
* corresponding to the autofs fs we want to open.
|
||||
*/
|
||||
|
||||
filp = dentry_open(path.dentry, path.mnt, O_RDONLY,
|
||||
current_cred());
|
||||
filp = dentry_open(&path, O_RDONLY, current_cred());
|
||||
path_put(&path);
|
||||
if (IS_ERR(filp)) {
|
||||
err = PTR_ERR(filp);
|
||||
goto out;
|
||||
|
|
|
@ -32,7 +32,7 @@ static long autofs4_root_ioctl(struct file *,unsigned int,unsigned long);
|
|||
static long autofs4_root_compat_ioctl(struct file *,unsigned int,unsigned long);
|
||||
#endif
|
||||
static int autofs4_dir_open(struct inode *inode, struct file *file);
|
||||
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, struct nameidata *);
|
||||
static struct dentry *autofs4_lookup(struct inode *,struct dentry *, unsigned int);
|
||||
static struct vfsmount *autofs4_d_automount(struct path *);
|
||||
static int autofs4_d_manage(struct dentry *, bool);
|
||||
static void autofs4_dentry_release(struct dentry *);
|
||||
|
@ -458,7 +458,7 @@ int autofs4_d_manage(struct dentry *dentry, bool rcu_walk)
|
|||
}
|
||||
|
||||
/* Lookups in the root directory */
|
||||
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct autofs_sb_info *sbi;
|
||||
struct autofs_info *ino;
|
||||
|
|
|
@ -173,13 +173,13 @@ static const struct file_operations bad_file_ops =
|
|||
};
|
||||
|
||||
static int bad_inode_create (struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, struct nameidata *nd)
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static struct dentry *bad_inode_lookup(struct inode *dir,
|
||||
struct dentry *dentry, struct nameidata *nd)
|
||||
struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ static int befs_readdir(struct file *, void *, filldir_t);
|
|||
static int befs_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||
static int befs_readpage(struct file *file, struct page *page);
|
||||
static sector_t befs_bmap(struct address_space *mapping, sector_t block);
|
||||
static struct dentry *befs_lookup(struct inode *, struct dentry *, struct nameidata *);
|
||||
static struct dentry *befs_lookup(struct inode *, struct dentry *, unsigned int);
|
||||
static struct inode *befs_iget(struct super_block *, unsigned long);
|
||||
static struct inode *befs_alloc_inode(struct super_block *sb);
|
||||
static void befs_destroy_inode(struct inode *inode);
|
||||
|
@ -159,7 +159,7 @@ befs_get_block(struct inode *inode, sector_t block,
|
|||
}
|
||||
|
||||
static struct dentry *
|
||||
befs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
befs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct super_block *sb = dir->i_sb;
|
||||
|
|
|
@ -85,7 +85,7 @@ const struct file_operations bfs_dir_operations = {
|
|||
extern void dump_imap(const char *, struct super_block *);
|
||||
|
||||
static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
|
@ -133,7 +133,7 @@ static int bfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
}
|
||||
|
||||
static struct dentry *bfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct buffer_head *bh;
|
||||
|
|
|
@ -1710,3 +1710,39 @@ int __invalidate_device(struct block_device *bdev, bool kill_dirty)
|
|||
return res;
|
||||
}
|
||||
EXPORT_SYMBOL(__invalidate_device);
|
||||
|
||||
void iterate_bdevs(void (*func)(struct block_device *, void *), void *arg)
|
||||
{
|
||||
struct inode *inode, *old_inode = NULL;
|
||||
|
||||
spin_lock(&inode_sb_list_lock);
|
||||
list_for_each_entry(inode, &blockdev_superblock->s_inodes, i_sb_list) {
|
||||
struct address_space *mapping = inode->i_mapping;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
if (inode->i_state & (I_FREEING|I_WILL_FREE|I_NEW) ||
|
||||
mapping->nrpages == 0) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
continue;
|
||||
}
|
||||
__iget(inode);
|
||||
spin_unlock(&inode->i_lock);
|
||||
spin_unlock(&inode_sb_list_lock);
|
||||
/*
|
||||
* We hold a reference to 'inode' so it couldn't have been
|
||||
* removed from s_inodes list while we dropped the
|
||||
* inode_sb_list_lock. We cannot iput the inode now as we can
|
||||
* be holding the last reference and we cannot iput it under
|
||||
* inode_sb_list_lock. So we keep the reference and iput it
|
||||
* later.
|
||||
*/
|
||||
iput(old_inode);
|
||||
old_inode = inode;
|
||||
|
||||
func(I_BDEV(inode), arg);
|
||||
|
||||
spin_lock(&inode_sb_list_lock);
|
||||
}
|
||||
spin_unlock(&inode_sb_list_lock);
|
||||
iput(old_inode);
|
||||
}
|
||||
|
|
|
@ -4247,7 +4247,7 @@ static void btrfs_dentry_release(struct dentry *dentry)
|
|||
}
|
||||
|
||||
static struct dentry *btrfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct dentry *ret;
|
||||
|
||||
|
@ -4893,7 +4893,7 @@ out_unlock:
|
|||
}
|
||||
|
||||
static int btrfs_create(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, struct nameidata *nd)
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
struct btrfs_trans_handle *trans;
|
||||
struct btrfs_root *root = BTRFS_I(dir)->root;
|
||||
|
@ -6987,7 +6987,7 @@ void btrfs_destroy_inode(struct inode *inode)
|
|||
struct btrfs_ordered_extent *ordered;
|
||||
struct btrfs_root *root = BTRFS_I(inode)->root;
|
||||
|
||||
WARN_ON(!list_empty(&inode->i_dentry));
|
||||
WARN_ON(!hlist_empty(&inode->i_dentry));
|
||||
WARN_ON(inode->i_data.nrpages);
|
||||
WARN_ON(BTRFS_I(inode)->outstanding_extents);
|
||||
WARN_ON(BTRFS_I(inode)->reserved_extents);
|
||||
|
|
|
@ -3268,7 +3268,7 @@ static long btrfs_ioctl_balance(struct file *file, void __user *arg)
|
|||
if (fs_info->sb->s_flags & MS_RDONLY)
|
||||
return -EROFS;
|
||||
|
||||
ret = mnt_want_write(file->f_path.mnt);
|
||||
ret = mnt_want_write_file(file);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
|
@ -3338,7 +3338,7 @@ out_bargs:
|
|||
out:
|
||||
mutex_unlock(&fs_info->balance_mutex);
|
||||
mutex_unlock(&fs_info->volume_mutex);
|
||||
mnt_drop_write(file->f_path.mnt);
|
||||
mnt_drop_write_file(file);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
|
@ -1068,7 +1068,8 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|||
}
|
||||
|
||||
bdev = fs_devices->latest_bdev;
|
||||
s = sget(fs_type, btrfs_test_super, btrfs_set_super, fs_info);
|
||||
s = sget(fs_type, btrfs_test_super, btrfs_set_super, flags | MS_NOSEC,
|
||||
fs_info);
|
||||
if (IS_ERR(s)) {
|
||||
error = PTR_ERR(s);
|
||||
goto error_close_devices;
|
||||
|
@ -1082,7 +1083,6 @@ static struct dentry *btrfs_mount(struct file_system_type *fs_type, int flags,
|
|||
} else {
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
s->s_flags = flags | MS_NOSEC;
|
||||
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
|
||||
btrfs_sb(s)->bdev_holder = fs_type;
|
||||
error = btrfs_fill_super(s, fs_devices, data,
|
||||
|
|
|
@ -567,7 +567,7 @@ lookup_again:
|
|||
if (ret < 0)
|
||||
goto create_error;
|
||||
start = jiffies;
|
||||
ret = vfs_create(dir->d_inode, next, S_IFREG, NULL);
|
||||
ret = vfs_create(dir->d_inode, next, S_IFREG, true);
|
||||
cachefiles_hist(cachefiles_create_histogram, start);
|
||||
if (ret < 0)
|
||||
goto create_error;
|
||||
|
|
|
@ -891,6 +891,7 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
|
|||
struct cachefiles_cache *cache;
|
||||
mm_segment_t old_fs;
|
||||
struct file *file;
|
||||
struct path path;
|
||||
loff_t pos, eof;
|
||||
size_t len;
|
||||
void *data;
|
||||
|
@ -916,10 +917,9 @@ int cachefiles_write_page(struct fscache_storage *op, struct page *page)
|
|||
|
||||
/* write the page to the backing filesystem and let it store it in its
|
||||
* own time */
|
||||
dget(object->backer);
|
||||
mntget(cache->mnt);
|
||||
file = dentry_open(object->backer, cache->mnt, O_RDWR,
|
||||
cache->cache_cred);
|
||||
path.mnt = cache->mnt;
|
||||
path.dentry = object->backer;
|
||||
file = dentry_open(&path, O_RDWR, cache->cache_cred);
|
||||
if (IS_ERR(file)) {
|
||||
ret = PTR_ERR(file);
|
||||
} else {
|
||||
|
|
|
@ -576,7 +576,7 @@ static int is_root_ceph_dentry(struct inode *inode, struct dentry *dentry)
|
|||
* the MDS so that it gets our 'caps wanted' value in a single op.
|
||||
*/
|
||||
static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
|
@ -594,14 +594,6 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
|||
if (err < 0)
|
||||
return ERR_PTR(err);
|
||||
|
||||
/* open (but not create!) intent? */
|
||||
if (nd &&
|
||||
(nd->flags & LOOKUP_OPEN) &&
|
||||
!(nd->intent.open.flags & O_CREAT)) {
|
||||
int mode = nd->intent.open.create_mode & ~current->fs->umask;
|
||||
return ceph_lookup_open(dir, dentry, nd, mode, 1);
|
||||
}
|
||||
|
||||
/* can we conclude ENOENT locally? */
|
||||
if (dentry->d_inode == NULL) {
|
||||
struct ceph_inode_info *ci = ceph_inode(dir);
|
||||
|
@ -642,13 +634,51 @@ static struct dentry *ceph_lookup(struct inode *dir, struct dentry *dentry,
|
|||
return dentry;
|
||||
}
|
||||
|
||||
int ceph_atomic_open(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, unsigned flags, umode_t mode,
|
||||
int *opened)
|
||||
{
|
||||
int err;
|
||||
struct dentry *res = NULL;
|
||||
|
||||
if (!(flags & O_CREAT)) {
|
||||
if (dentry->d_name.len > NAME_MAX)
|
||||
return -ENAMETOOLONG;
|
||||
|
||||
err = ceph_init_dentry(dentry);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
return ceph_lookup_open(dir, dentry, file, flags, mode, opened);
|
||||
}
|
||||
|
||||
if (d_unhashed(dentry)) {
|
||||
res = ceph_lookup(dir, dentry, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
if (res)
|
||||
dentry = res;
|
||||
}
|
||||
|
||||
/* We don't deal with positive dentries here */
|
||||
if (dentry->d_inode)
|
||||
return finish_no_open(file, res);
|
||||
|
||||
*opened |= FILE_CREATED;
|
||||
err = ceph_lookup_open(dir, dentry, file, flags, mode, opened);
|
||||
dput(res);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we do a create but get no trace back from the MDS, follow up with
|
||||
* a lookup (the VFS expects us to link up the provided dentry).
|
||||
*/
|
||||
int ceph_handle_notrace_create(struct inode *dir, struct dentry *dentry)
|
||||
{
|
||||
struct dentry *result = ceph_lookup(dir, dentry, NULL);
|
||||
struct dentry *result = ceph_lookup(dir, dentry, 0);
|
||||
|
||||
if (result && !IS_ERR(result)) {
|
||||
/*
|
||||
|
@ -700,25 +730,9 @@ static int ceph_mknod(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
|
||||
static int ceph_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
dout("create in dir %p dentry %p name '%.*s'\n",
|
||||
dir, dentry, dentry->d_name.len, dentry->d_name.name);
|
||||
|
||||
if (ceph_snap(dir) != CEPH_NOSNAP)
|
||||
return -EROFS;
|
||||
|
||||
if (nd) {
|
||||
BUG_ON((nd->flags & LOOKUP_OPEN) == 0);
|
||||
dentry = ceph_lookup_open(dir, dentry, nd, mode, 0);
|
||||
/* hrm, what should i do here if we get aliased? */
|
||||
if (IS_ERR(dentry))
|
||||
return PTR_ERR(dentry);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* fall back to mknod */
|
||||
return ceph_mknod(dir, dentry, (mode & ~S_IFMT) | S_IFREG, 0);
|
||||
return ceph_mknod(dir, dentry, mode, 0);
|
||||
}
|
||||
|
||||
static int ceph_symlink(struct inode *dir, struct dentry *dentry,
|
||||
|
@ -1028,12 +1042,12 @@ static int dir_lease_is_valid(struct inode *dir, struct dentry *dentry)
|
|||
/*
|
||||
* Check if cached dentry can be trusted.
|
||||
*/
|
||||
static int ceph_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
static int ceph_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
int valid = 0;
|
||||
struct inode *dir;
|
||||
|
||||
if (nd && nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
dout("d_revalidate %p '%.*s' inode %p offset %lld\n", dentry,
|
||||
|
@ -1080,7 +1094,7 @@ static void ceph_d_release(struct dentry *dentry)
|
|||
}
|
||||
|
||||
static int ceph_snapdir_d_revalidate(struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
/*
|
||||
* Eventually, we'll want to revalidate snapped metadata
|
||||
|
@ -1357,6 +1371,7 @@ const struct inode_operations ceph_dir_iops = {
|
|||
.rmdir = ceph_unlink,
|
||||
.rename = ceph_rename,
|
||||
.create = ceph_create,
|
||||
.atomic_open = ceph_atomic_open,
|
||||
};
|
||||
|
||||
const struct dentry_operations ceph_dentry_ops = {
|
||||
|
|
|
@ -213,22 +213,15 @@ out:
|
|||
* may_open() fails, the struct *file gets cleaned up (i.e.
|
||||
* ceph_release gets called). So fear not!
|
||||
*/
|
||||
/*
|
||||
* flags
|
||||
* path_lookup_open -> LOOKUP_OPEN
|
||||
* path_lookup_create -> LOOKUP_OPEN|LOOKUP_CREATE
|
||||
*/
|
||||
struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd, int mode,
|
||||
int locked_dir)
|
||||
int ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
||||
struct file *file, unsigned flags, umode_t mode,
|
||||
int *opened)
|
||||
{
|
||||
struct ceph_fs_client *fsc = ceph_sb_to_client(dir->i_sb);
|
||||
struct ceph_mds_client *mdsc = fsc->mdsc;
|
||||
struct file *file;
|
||||
struct ceph_mds_request *req;
|
||||
struct dentry *ret;
|
||||
int err;
|
||||
int flags = nd->intent.open.flags;
|
||||
|
||||
dout("ceph_lookup_open dentry %p '%.*s' flags %d mode 0%o\n",
|
||||
dentry, dentry->d_name.len, dentry->d_name.name, flags, mode);
|
||||
|
@ -236,7 +229,7 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
|||
/* do the open */
|
||||
req = prepare_open_request(dir->i_sb, flags, mode);
|
||||
if (IS_ERR(req))
|
||||
return ERR_CAST(req);
|
||||
return PTR_ERR(req);
|
||||
req->r_dentry = dget(dentry);
|
||||
req->r_num_caps = 2;
|
||||
if (flags & O_CREAT) {
|
||||
|
@ -254,14 +247,17 @@ struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
|||
err = ceph_handle_notrace_create(dir, dentry);
|
||||
if (err)
|
||||
goto out;
|
||||
file = lookup_instantiate_filp(nd, req->r_dentry, ceph_open);
|
||||
if (IS_ERR(file))
|
||||
err = PTR_ERR(file);
|
||||
err = finish_open(file, req->r_dentry, ceph_open, opened);
|
||||
out:
|
||||
ret = ceph_finish_lookup(req, dentry, err);
|
||||
ceph_mdsc_put_request(req);
|
||||
dout("ceph_lookup_open result=%p\n", ret);
|
||||
return ret;
|
||||
|
||||
if (IS_ERR(ret))
|
||||
return PTR_ERR(ret);
|
||||
|
||||
dput(ret);
|
||||
return err;
|
||||
}
|
||||
|
||||
int ceph_release(struct inode *inode, struct file *file)
|
||||
|
|
|
@ -871,7 +871,7 @@ static struct dentry *ceph_mount(struct file_system_type *fs_type,
|
|||
|
||||
if (ceph_test_opt(fsc->client, NOSHARE))
|
||||
compare_super = NULL;
|
||||
sb = sget(fs_type, compare_super, ceph_set_super, fsc);
|
||||
sb = sget(fs_type, compare_super, ceph_set_super, flags, fsc);
|
||||
if (IS_ERR(sb)) {
|
||||
res = ERR_CAST(sb);
|
||||
goto out;
|
||||
|
|
|
@ -806,9 +806,9 @@ extern int ceph_copy_from_page_vector(struct page **pages,
|
|||
loff_t off, size_t len);
|
||||
extern struct page **ceph_alloc_page_vector(int num_pages, gfp_t flags);
|
||||
extern int ceph_open(struct inode *inode, struct file *file);
|
||||
extern struct dentry *ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd, int mode,
|
||||
int locked_dir);
|
||||
extern int ceph_lookup_open(struct inode *dir, struct dentry *dentry,
|
||||
struct file *od, unsigned flags,
|
||||
umode_t mode, int *opened);
|
||||
extern int ceph_release(struct inode *inode, struct file *filp);
|
||||
|
||||
/* dir.c */
|
||||
|
|
|
@ -257,7 +257,6 @@ cifs_alloc_inode(struct super_block *sb)
|
|||
static void cifs_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(cifs_inode_cachep, CIFS_I(inode));
|
||||
}
|
||||
|
||||
|
@ -638,7 +637,10 @@ cifs_do_mount(struct file_system_type *fs_type,
|
|||
mnt_data.cifs_sb = cifs_sb;
|
||||
mnt_data.flags = flags;
|
||||
|
||||
sb = sget(fs_type, cifs_match_super, cifs_set_super, &mnt_data);
|
||||
/* BB should we make this contingent on mount parm? */
|
||||
flags |= MS_NODIRATIME | MS_NOATIME;
|
||||
|
||||
sb = sget(fs_type, cifs_match_super, cifs_set_super, flags, &mnt_data);
|
||||
if (IS_ERR(sb)) {
|
||||
root = ERR_CAST(sb);
|
||||
cifs_umount(cifs_sb);
|
||||
|
@ -649,10 +651,6 @@ cifs_do_mount(struct file_system_type *fs_type,
|
|||
cFYI(1, "Use existing superblock");
|
||||
cifs_umount(cifs_sb);
|
||||
} else {
|
||||
sb->s_flags = flags;
|
||||
/* BB should we make this contingent on mount parm? */
|
||||
sb->s_flags |= MS_NODIRATIME | MS_NOATIME;
|
||||
|
||||
rc = cifs_read_super(sb);
|
||||
if (rc) {
|
||||
root = ERR_PTR(rc);
|
||||
|
@ -778,6 +776,7 @@ struct file_system_type cifs_fs_type = {
|
|||
};
|
||||
const struct inode_operations cifs_dir_inode_ops = {
|
||||
.create = cifs_create,
|
||||
.atomic_open = cifs_atomic_open,
|
||||
.lookup = cifs_lookup,
|
||||
.getattr = cifs_getattr,
|
||||
.unlink = cifs_unlink,
|
||||
|
|
|
@ -45,9 +45,12 @@ extern const struct address_space_operations cifs_addr_ops_smallbuf;
|
|||
extern const struct inode_operations cifs_dir_inode_ops;
|
||||
extern struct inode *cifs_root_iget(struct super_block *);
|
||||
extern int cifs_create(struct inode *, struct dentry *, umode_t,
|
||||
struct nameidata *);
|
||||
bool excl);
|
||||
extern int cifs_atomic_open(struct inode *, struct dentry *,
|
||||
struct file *, unsigned, umode_t,
|
||||
int *);
|
||||
extern struct dentry *cifs_lookup(struct inode *, struct dentry *,
|
||||
struct nameidata *);
|
||||
unsigned int);
|
||||
extern int cifs_unlink(struct inode *dir, struct dentry *dentry);
|
||||
extern int cifs_hardlink(struct dentry *, struct inode *, struct dentry *);
|
||||
extern int cifs_mknod(struct inode *, struct dentry *, umode_t, dev_t);
|
||||
|
|
450
fs/cifs/dir.c
450
fs/cifs/dir.c
|
@ -133,100 +133,133 @@ cifs_bp_rename_retry:
|
|||
return full_path;
|
||||
}
|
||||
|
||||
/*
|
||||
* Don't allow the separator character in a path component.
|
||||
* The VFS will not allow "/", but "\" is allowed by posix.
|
||||
*/
|
||||
static int
|
||||
check_name(struct dentry *direntry)
|
||||
{
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(direntry->d_sb);
|
||||
int i;
|
||||
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
|
||||
for (i = 0; i < direntry->d_name.len; i++) {
|
||||
if (direntry->d_name.name[i] == '\\') {
|
||||
cFYI(1, "Invalid file name");
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
/* Inode operations in similar order to how they appear in Linux file fs.h */
|
||||
|
||||
int
|
||||
cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
static int cifs_do_create(struct inode *inode, struct dentry *direntry,
|
||||
int xid, struct tcon_link *tlink, unsigned oflags,
|
||||
umode_t mode, __u32 *oplock, __u16 *fileHandle,
|
||||
int *created)
|
||||
{
|
||||
int rc = -ENOENT;
|
||||
int xid;
|
||||
int create_options = CREATE_NOT_DIR;
|
||||
__u32 oplock = 0;
|
||||
int oflags;
|
||||
/*
|
||||
* BB below access is probably too much for mknod to request
|
||||
* but we have to do query and setpathinfo so requesting
|
||||
* less could fail (unless we want to request getatr and setatr
|
||||
* permissions (only). At least for POSIX we do not have to
|
||||
* request so much.
|
||||
*/
|
||||
int desiredAccess = GENERIC_READ | GENERIC_WRITE;
|
||||
__u16 fileHandle;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
int desiredAccess;
|
||||
struct cifs_sb_info *cifs_sb = CIFS_SB(inode->i_sb);
|
||||
struct cifs_tcon *tcon = tlink_tcon(tlink);
|
||||
char *full_path = NULL;
|
||||
FILE_ALL_INFO *buf = NULL;
|
||||
struct inode *newinode = NULL;
|
||||
int disposition = FILE_OVERWRITE_IF;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cifs_sb = CIFS_SB(inode->i_sb);
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
FreeXid(xid);
|
||||
return PTR_ERR(tlink);
|
||||
}
|
||||
tcon = tlink_tcon(tlink);
|
||||
int disposition;
|
||||
|
||||
*oplock = 0;
|
||||
if (tcon->ses->server->oplocks)
|
||||
oplock = REQ_OPLOCK;
|
||||
|
||||
if (nd)
|
||||
oflags = nd->intent.open.file->f_flags;
|
||||
else
|
||||
oflags = O_RDONLY | O_CREAT;
|
||||
*oplock = REQ_OPLOCK;
|
||||
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
if (full_path == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cifs_create_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
|
||||
!tcon->broken_posix_open &&
|
||||
(CIFS_UNIX_POSIX_PATH_OPS_CAP &
|
||||
le64_to_cpu(tcon->fsUnixInfo.Capability))) {
|
||||
rc = cifs_posix_open(full_path, &newinode,
|
||||
inode->i_sb, mode, oflags, &oplock, &fileHandle, xid);
|
||||
/* EIO could indicate that (posix open) operation is not
|
||||
supported, despite what server claimed in capability
|
||||
negotiation. EREMOTE indicates DFS junction, which is not
|
||||
handled in posix open */
|
||||
|
||||
if (rc == 0) {
|
||||
if (newinode == NULL) /* query inode info */
|
||||
inode->i_sb, mode, oflags, oplock, fileHandle, xid);
|
||||
switch (rc) {
|
||||
case 0:
|
||||
if (newinode == NULL) {
|
||||
/* query inode info */
|
||||
goto cifs_create_get_file_info;
|
||||
else /* success, no need to query */
|
||||
goto cifs_create_set_dentry;
|
||||
} else if ((rc != -EIO) && (rc != -EREMOTE) &&
|
||||
(rc != -EOPNOTSUPP) && (rc != -EINVAL))
|
||||
goto cifs_create_out;
|
||||
/* else fallthrough to retry, using older open call, this is
|
||||
case where server does not support this SMB level, and
|
||||
falsely claims capability (also get here for DFS case
|
||||
which should be rare for path not covered on files) */
|
||||
}
|
||||
|
||||
if (!S_ISREG(newinode->i_mode)) {
|
||||
/*
|
||||
* The server may allow us to open things like
|
||||
* FIFOs, but the client isn't set up to deal
|
||||
* with that. If it's not a regular file, just
|
||||
* close it and proceed as if it were a normal
|
||||
* lookup.
|
||||
*/
|
||||
CIFSSMBClose(xid, tcon, *fileHandle);
|
||||
goto cifs_create_get_file_info;
|
||||
}
|
||||
/* success, no need to query */
|
||||
goto cifs_create_set_dentry;
|
||||
|
||||
case -ENOENT:
|
||||
goto cifs_create_get_file_info;
|
||||
|
||||
case -EIO:
|
||||
case -EINVAL:
|
||||
/*
|
||||
* EIO could indicate that (posix open) operation is not
|
||||
* supported, despite what server claimed in capability
|
||||
* negotiation.
|
||||
*
|
||||
* POSIX open in samba versions 3.3.1 and earlier could
|
||||
* incorrectly fail with invalid parameter.
|
||||
*/
|
||||
tcon->broken_posix_open = true;
|
||||
break;
|
||||
|
||||
case -EREMOTE:
|
||||
case -EOPNOTSUPP:
|
||||
/*
|
||||
* EREMOTE indicates DFS junction, which is not handled
|
||||
* in posix open. If either that or op not supported
|
||||
* returned, follow the normal lookup.
|
||||
*/
|
||||
break;
|
||||
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
/*
|
||||
* fallthrough to retry, using older open call, this is case
|
||||
* where server does not support this SMB level, and falsely
|
||||
* claims capability (also get here for DFS case which should be
|
||||
* rare for path not covered on files)
|
||||
*/
|
||||
}
|
||||
|
||||
if (nd) {
|
||||
/* if the file is going to stay open, then we
|
||||
need to set the desired access properly */
|
||||
desiredAccess = 0;
|
||||
if (OPEN_FMODE(oflags) & FMODE_READ)
|
||||
desiredAccess |= GENERIC_READ; /* is this too little? */
|
||||
if (OPEN_FMODE(oflags) & FMODE_WRITE)
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
desiredAccess = 0;
|
||||
if (OPEN_FMODE(oflags) & FMODE_READ)
|
||||
desiredAccess |= GENERIC_READ; /* is this too little? */
|
||||
if (OPEN_FMODE(oflags) & FMODE_WRITE)
|
||||
desiredAccess |= GENERIC_WRITE;
|
||||
|
||||
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
|
||||
disposition = FILE_CREATE;
|
||||
else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
|
||||
disposition = FILE_OVERWRITE_IF;
|
||||
else if ((oflags & O_CREAT) == O_CREAT)
|
||||
disposition = FILE_OPEN_IF;
|
||||
else
|
||||
cFYI(1, "Create flag not set in create function");
|
||||
}
|
||||
disposition = FILE_OVERWRITE_IF;
|
||||
if ((oflags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
|
||||
disposition = FILE_CREATE;
|
||||
else if ((oflags & (O_CREAT | O_TRUNC)) == (O_CREAT | O_TRUNC))
|
||||
disposition = FILE_OVERWRITE_IF;
|
||||
else if ((oflags & O_CREAT) == O_CREAT)
|
||||
disposition = FILE_OPEN_IF;
|
||||
else
|
||||
cFYI(1, "Create flag not set in create function");
|
||||
|
||||
/* BB add processing to set equivalent of mode - e.g. via CreateX with
|
||||
ACLs */
|
||||
|
@ -234,7 +267,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
|
||||
if (buf == NULL) {
|
||||
rc = -ENOMEM;
|
||||
goto cifs_create_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -250,7 +283,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
if (tcon->ses->capabilities & CAP_NT_SMBS)
|
||||
rc = CIFSSMBOpen(xid, tcon, full_path, disposition,
|
||||
desiredAccess, create_options,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
fileHandle, oplock, buf, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
else
|
||||
rc = -EIO; /* no NT SMB support fall into legacy open below */
|
||||
|
@ -259,17 +292,17 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
/* old server, retry the open legacy style */
|
||||
rc = SMBLegacyOpen(xid, tcon, full_path, disposition,
|
||||
desiredAccess, create_options,
|
||||
&fileHandle, &oplock, buf, cifs_sb->local_nls,
|
||||
fileHandle, oplock, buf, cifs_sb->local_nls,
|
||||
cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
|
||||
}
|
||||
if (rc) {
|
||||
cFYI(1, "cifs_create returned 0x%x", rc);
|
||||
goto cifs_create_out;
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* If Open reported that we actually created a file
|
||||
then we now have to set the mode if possible */
|
||||
if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
|
||||
if ((tcon->unix_ext) && (*oplock & CIFS_CREATE_ACTION)) {
|
||||
struct cifs_unix_set_info_args args = {
|
||||
.mode = mode,
|
||||
.ctime = NO_CHANGE_64,
|
||||
|
@ -278,6 +311,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
.device = 0,
|
||||
};
|
||||
|
||||
*created |= FILE_CREATED;
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
|
||||
args.uid = (__u64) current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
|
@ -288,7 +322,7 @@ cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
|||
args.uid = NO_CHANGE_64;
|
||||
args.gid = NO_CHANGE_64;
|
||||
}
|
||||
CIFSSMBUnixSetFileInfo(xid, tcon, &args, fileHandle,
|
||||
CIFSSMBUnixSetFileInfo(xid, tcon, &args, *fileHandle,
|
||||
current->tgid);
|
||||
} else {
|
||||
/* BB implement mode setting via Windows security
|
||||
|
@ -305,11 +339,11 @@ cifs_create_get_file_info:
|
|||
inode->i_sb, xid);
|
||||
else {
|
||||
rc = cifs_get_inode_info(&newinode, full_path, buf,
|
||||
inode->i_sb, xid, &fileHandle);
|
||||
inode->i_sb, xid, fileHandle);
|
||||
if (newinode) {
|
||||
if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
|
||||
newinode->i_mode = mode;
|
||||
if ((oplock & CIFS_CREATE_ACTION) &&
|
||||
if ((*oplock & CIFS_CREATE_ACTION) &&
|
||||
(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
|
||||
newinode->i_uid = current_fsuid();
|
||||
if (inode->i_mode & S_ISGID)
|
||||
|
@ -321,40 +355,139 @@ cifs_create_get_file_info:
|
|||
}
|
||||
|
||||
cifs_create_set_dentry:
|
||||
if (rc == 0)
|
||||
d_instantiate(direntry, newinode);
|
||||
else
|
||||
if (rc != 0) {
|
||||
cFYI(1, "Create worked, get_inode_info failed rc = %d", rc);
|
||||
|
||||
if (newinode && nd) {
|
||||
struct cifsFileInfo *pfile_info;
|
||||
struct file *filp;
|
||||
|
||||
filp = lookup_instantiate_filp(nd, direntry, generic_file_open);
|
||||
if (IS_ERR(filp)) {
|
||||
rc = PTR_ERR(filp);
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
goto cifs_create_out;
|
||||
}
|
||||
|
||||
pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
|
||||
if (pfile_info == NULL) {
|
||||
fput(filp);
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
} else {
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
goto out;
|
||||
}
|
||||
d_drop(direntry);
|
||||
d_add(direntry, newinode);
|
||||
|
||||
cifs_create_out:
|
||||
/* ENOENT for create? How weird... */
|
||||
rc = -ENOENT;
|
||||
if (!newinode) {
|
||||
CIFSSMBClose(xid, tcon, *fileHandle);
|
||||
goto out;
|
||||
}
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
kfree(buf);
|
||||
kfree(full_path);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int
|
||||
cifs_atomic_open(struct inode *inode, struct dentry *direntry,
|
||||
struct file *file, unsigned oflags, umode_t mode,
|
||||
int *opened)
|
||||
{
|
||||
int rc;
|
||||
int xid;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *tcon;
|
||||
__u16 fileHandle;
|
||||
__u32 oplock;
|
||||
struct file *filp;
|
||||
struct cifsFileInfo *pfile_info;
|
||||
|
||||
/* Posix open is only called (at lookup time) for file create now. For
|
||||
* opens (rather than creates), because we do not know if it is a file
|
||||
* or directory yet, and current Samba no longer allows us to do posix
|
||||
* open on dirs, we could end up wasting an open call on what turns out
|
||||
* to be a dir. For file opens, we wait to call posix open till
|
||||
* cifs_open. It could be added to atomic_open in the future but the
|
||||
* performance tradeoff of the extra network request when EISDIR or
|
||||
* EACCES is returned would have to be weighed against the 50% reduction
|
||||
* in network traffic in the other paths.
|
||||
*/
|
||||
if (!(oflags & O_CREAT)) {
|
||||
struct dentry *res = cifs_lookup(inode, direntry, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
return finish_no_open(file, res);
|
||||
}
|
||||
|
||||
rc = check_name(direntry);
|
||||
if (rc)
|
||||
return rc;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
cFYI(1, "parent inode = 0x%p name is: %s and dentry = 0x%p",
|
||||
inode, direntry->d_name.name, direntry);
|
||||
|
||||
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
|
||||
filp = ERR_CAST(tlink);
|
||||
if (IS_ERR(tlink))
|
||||
goto free_xid;
|
||||
|
||||
tcon = tlink_tcon(tlink);
|
||||
|
||||
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
|
||||
&oplock, &fileHandle, opened);
|
||||
|
||||
if (rc)
|
||||
goto out;
|
||||
|
||||
rc = finish_open(file, direntry, generic_file_open, opened);
|
||||
if (rc) {
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
goto out;
|
||||
}
|
||||
|
||||
pfile_info = cifs_new_fileinfo(fileHandle, filp, tlink, oplock);
|
||||
if (pfile_info == NULL) {
|
||||
CIFSSMBClose(xid, tcon, fileHandle);
|
||||
fput(filp);
|
||||
rc = -ENOMEM;
|
||||
}
|
||||
|
||||
out:
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid:
|
||||
FreeXid(xid);
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_create(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
bool excl)
|
||||
{
|
||||
int rc;
|
||||
int xid = GetXid();
|
||||
/*
|
||||
* BB below access is probably too much for mknod to request
|
||||
* but we have to do query and setpathinfo so requesting
|
||||
* less could fail (unless we want to request getatr and setatr
|
||||
* permissions (only). At least for POSIX we do not have to
|
||||
* request so much.
|
||||
*/
|
||||
unsigned oflags = O_EXCL | O_CREAT | O_RDWR;
|
||||
struct tcon_link *tlink;
|
||||
__u16 fileHandle;
|
||||
__u32 oplock;
|
||||
int created = FILE_CREATED;
|
||||
|
||||
cFYI(1, "cifs_create parent inode = 0x%p name is: %s and dentry = 0x%p",
|
||||
inode, direntry->d_name.name, direntry);
|
||||
|
||||
tlink = cifs_sb_tlink(CIFS_SB(inode->i_sb));
|
||||
rc = PTR_ERR(tlink);
|
||||
if (IS_ERR(tlink))
|
||||
goto free_xid;
|
||||
|
||||
rc = cifs_do_create(inode, direntry, xid, tlink, oflags, mode,
|
||||
&oplock, &fileHandle, &created);
|
||||
if (!rc)
|
||||
CIFSSMBClose(xid, tlink_tcon(tlink), fileHandle);
|
||||
|
||||
cifs_put_tlink(tlink);
|
||||
free_xid:
|
||||
FreeXid(xid);
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
int cifs_mknod(struct inode *inode, struct dentry *direntry, umode_t mode,
|
||||
dev_t device_number)
|
||||
{
|
||||
|
@ -488,20 +621,15 @@ mknod_out:
|
|||
|
||||
struct dentry *
|
||||
cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
int xid;
|
||||
int rc = 0; /* to get around spurious gcc warning, set to zero here */
|
||||
__u32 oplock;
|
||||
__u16 fileHandle = 0;
|
||||
bool posix_open = false;
|
||||
struct cifs_sb_info *cifs_sb;
|
||||
struct tcon_link *tlink;
|
||||
struct cifs_tcon *pTcon;
|
||||
struct cifsFileInfo *cfile;
|
||||
struct inode *newInode = NULL;
|
||||
char *full_path = NULL;
|
||||
struct file *filp;
|
||||
|
||||
xid = GetXid();
|
||||
|
||||
|
@ -518,31 +646,9 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
}
|
||||
pTcon = tlink_tcon(tlink);
|
||||
|
||||
oplock = pTcon->ses->server->oplocks ? REQ_OPLOCK : 0;
|
||||
|
||||
/*
|
||||
* Don't allow the separator character in a path component.
|
||||
* The VFS will not allow "/", but "\" is allowed by posix.
|
||||
*/
|
||||
if (!(cifs_sb->mnt_cifs_flags & CIFS_MOUNT_POSIX_PATHS)) {
|
||||
int i;
|
||||
for (i = 0; i < direntry->d_name.len; i++)
|
||||
if (direntry->d_name.name[i] == '\\') {
|
||||
cFYI(1, "Invalid file name");
|
||||
rc = -EINVAL;
|
||||
goto lookup_out;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* O_EXCL: optimize away the lookup, but don't hash the dentry. Let
|
||||
* the VFS handle the create.
|
||||
*/
|
||||
if (nd && (nd->flags & LOOKUP_EXCL)) {
|
||||
d_instantiate(direntry, NULL);
|
||||
rc = 0;
|
||||
rc = check_name(direntry);
|
||||
if (rc)
|
||||
goto lookup_out;
|
||||
}
|
||||
|
||||
/* can not grab the rename sem here since it would
|
||||
deadlock in the cases (beginning of sys_rename itself)
|
||||
|
@ -560,80 +666,16 @@ cifs_lookup(struct inode *parent_dir_inode, struct dentry *direntry,
|
|||
}
|
||||
cFYI(1, "Full path: %s inode = 0x%p", full_path, direntry->d_inode);
|
||||
|
||||
/* Posix open is only called (at lookup time) for file create now.
|
||||
* For opens (rather than creates), because we do not know if it
|
||||
* is a file or directory yet, and current Samba no longer allows
|
||||
* us to do posix open on dirs, we could end up wasting an open call
|
||||
* on what turns out to be a dir. For file opens, we wait to call posix
|
||||
* open till cifs_open. It could be added here (lookup) in the future
|
||||
* but the performance tradeoff of the extra network request when EISDIR
|
||||
* or EACCES is returned would have to be weighed against the 50%
|
||||
* reduction in network traffic in the other paths.
|
||||
*/
|
||||
if (pTcon->unix_ext) {
|
||||
if (nd && !(nd->flags & LOOKUP_DIRECTORY) &&
|
||||
(nd->flags & LOOKUP_OPEN) && !pTcon->broken_posix_open &&
|
||||
(nd->intent.open.file->f_flags & O_CREAT)) {
|
||||
rc = cifs_posix_open(full_path, &newInode,
|
||||
parent_dir_inode->i_sb,
|
||||
nd->intent.open.create_mode,
|
||||
nd->intent.open.file->f_flags, &oplock,
|
||||
&fileHandle, xid);
|
||||
/*
|
||||
* The check below works around a bug in POSIX
|
||||
* open in samba versions 3.3.1 and earlier where
|
||||
* open could incorrectly fail with invalid parameter.
|
||||
* If either that or op not supported returned, follow
|
||||
* the normal lookup.
|
||||
*/
|
||||
switch (rc) {
|
||||
case 0:
|
||||
/*
|
||||
* The server may allow us to open things like
|
||||
* FIFOs, but the client isn't set up to deal
|
||||
* with that. If it's not a regular file, just
|
||||
* close it and proceed as if it were a normal
|
||||
* lookup.
|
||||
*/
|
||||
if (newInode && !S_ISREG(newInode->i_mode)) {
|
||||
CIFSSMBClose(xid, pTcon, fileHandle);
|
||||
break;
|
||||
}
|
||||
case -ENOENT:
|
||||
posix_open = true;
|
||||
case -EOPNOTSUPP:
|
||||
break;
|
||||
default:
|
||||
pTcon->broken_posix_open = true;
|
||||
}
|
||||
}
|
||||
if (!posix_open)
|
||||
rc = cifs_get_inode_info_unix(&newInode, full_path,
|
||||
parent_dir_inode->i_sb, xid);
|
||||
} else
|
||||
rc = cifs_get_inode_info_unix(&newInode, full_path,
|
||||
parent_dir_inode->i_sb, xid);
|
||||
} else {
|
||||
rc = cifs_get_inode_info(&newInode, full_path, NULL,
|
||||
parent_dir_inode->i_sb, xid, NULL);
|
||||
}
|
||||
|
||||
if ((rc == 0) && (newInode != NULL)) {
|
||||
d_add(direntry, newInode);
|
||||
if (posix_open) {
|
||||
filp = lookup_instantiate_filp(nd, direntry,
|
||||
generic_file_open);
|
||||
if (IS_ERR(filp)) {
|
||||
rc = PTR_ERR(filp);
|
||||
CIFSSMBClose(xid, pTcon, fileHandle);
|
||||
goto lookup_out;
|
||||
}
|
||||
|
||||
cfile = cifs_new_fileinfo(fileHandle, filp, tlink,
|
||||
oplock);
|
||||
if (cfile == NULL) {
|
||||
fput(filp);
|
||||
CIFSSMBClose(xid, pTcon, fileHandle);
|
||||
rc = -ENOMEM;
|
||||
goto lookup_out;
|
||||
}
|
||||
}
|
||||
/* since paths are not looked up by component - the parent
|
||||
directories are presumed to be good here */
|
||||
renew_parental_timestamps(direntry);
|
||||
|
@ -658,9 +700,9 @@ lookup_out:
|
|||
}
|
||||
|
||||
static int
|
||||
cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
|
||||
cifs_d_revalidate(struct dentry *direntry, unsigned int flags)
|
||||
{
|
||||
if (nd && (nd->flags & LOOKUP_RCU))
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
if (direntry->d_inode) {
|
||||
|
@ -689,7 +731,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
|
|||
* This may be nfsd (or something), anyway, we can't see the
|
||||
* intent of this. So, since this can be for creation, drop it.
|
||||
*/
|
||||
if (!nd)
|
||||
if (!flags)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -697,7 +739,7 @@ cifs_d_revalidate(struct dentry *direntry, struct nameidata *nd)
|
|||
* case sensitive name which is specified by user if this is
|
||||
* for creation.
|
||||
*/
|
||||
if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
|
||||
if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
|
||||
return 0;
|
||||
|
||||
if (time_after(jiffies, direntry->d_time + HZ) || !lookupCacheEnabled)
|
||||
|
|
|
@ -800,7 +800,7 @@ cifs_find_inode(struct inode *inode, void *opaque)
|
|||
return 0;
|
||||
|
||||
/* if it's not a directory or has no dentries, then flag it */
|
||||
if (S_ISDIR(inode->i_mode) && !list_empty(&inode->i_dentry))
|
||||
if (S_ISDIR(inode->i_mode) && !hlist_empty(&inode->i_dentry))
|
||||
fattr->cf_flags |= CIFS_FATTR_INO_COLLISION;
|
||||
|
||||
return 1;
|
||||
|
@ -825,9 +825,10 @@ static bool
|
|||
inode_has_hashed_dentries(struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct hlist_node *p;
|
||||
|
||||
spin_lock(&inode->i_lock);
|
||||
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
|
||||
hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
|
||||
if (!d_unhashed(dentry) || IS_ROOT(dentry)) {
|
||||
spin_unlock(&inode->i_lock);
|
||||
return true;
|
||||
|
|
|
@ -89,17 +89,13 @@ int coda_cache_check(struct inode *inode, int mask)
|
|||
/* this won't do any harm: just flag all children */
|
||||
static void coda_flag_children(struct dentry *parent, int flag)
|
||||
{
|
||||
struct list_head *child;
|
||||
struct dentry *de;
|
||||
|
||||
spin_lock(&parent->d_lock);
|
||||
list_for_each(child, &parent->d_subdirs)
|
||||
{
|
||||
de = list_entry(child, struct dentry, d_u.d_child);
|
||||
list_for_each_entry(de, &parent->d_subdirs, d_u.d_child) {
|
||||
/* don't know what to do with negative dentries */
|
||||
if ( ! de->d_inode )
|
||||
continue;
|
||||
coda_flag_inode(de->d_inode, flag);
|
||||
if (de->d_inode )
|
||||
coda_flag_inode(de->d_inode, flag);
|
||||
}
|
||||
spin_unlock(&parent->d_lock);
|
||||
return;
|
||||
|
|
|
@ -30,8 +30,8 @@
|
|||
#include "coda_int.h"
|
||||
|
||||
/* dir inode-ops */
|
||||
static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, struct nameidata *nd);
|
||||
static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, struct nameidata *nd);
|
||||
static int coda_create(struct inode *dir, struct dentry *new, umode_t mode, bool excl);
|
||||
static struct dentry *coda_lookup(struct inode *dir, struct dentry *target, unsigned int flags);
|
||||
static int coda_link(struct dentry *old_dentry, struct inode *dir_inode,
|
||||
struct dentry *entry);
|
||||
static int coda_unlink(struct inode *dir_inode, struct dentry *entry);
|
||||
|
@ -46,7 +46,7 @@ static int coda_rename(struct inode *old_inode, struct dentry *old_dentry,
|
|||
static int coda_readdir(struct file *file, void *buf, filldir_t filldir);
|
||||
|
||||
/* dentry ops */
|
||||
static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd);
|
||||
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags);
|
||||
static int coda_dentry_delete(const struct dentry *);
|
||||
|
||||
/* support routines */
|
||||
|
@ -94,7 +94,7 @@ const struct file_operations coda_dir_operations = {
|
|||
|
||||
/* inode operations for directories */
|
||||
/* access routines: lookup, readlink, permission */
|
||||
static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, struct nameidata *nd)
|
||||
static struct dentry *coda_lookup(struct inode *dir, struct dentry *entry, unsigned int flags)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
const char *name = entry->d_name.name;
|
||||
|
@ -188,7 +188,7 @@ static inline void coda_dir_drop_nlink(struct inode *dir)
|
|||
}
|
||||
|
||||
/* creation routines: create, mknod, mkdir, link, symlink */
|
||||
static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, struct nameidata *nd)
|
||||
static int coda_create(struct inode *dir, struct dentry *de, umode_t mode, bool excl)
|
||||
{
|
||||
int error;
|
||||
const char *name=de->d_name.name;
|
||||
|
@ -536,12 +536,12 @@ out:
|
|||
}
|
||||
|
||||
/* called when a cache lookup succeeds */
|
||||
static int coda_dentry_revalidate(struct dentry *de, struct nameidata *nd)
|
||||
static int coda_dentry_revalidate(struct dentry *de, unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct coda_inode_info *cii;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
inode = de->d_inode;
|
||||
|
|
|
@ -442,7 +442,7 @@ static int configfs_attach_attr(struct configfs_dirent * sd, struct dentry * den
|
|||
|
||||
static struct dentry * configfs_lookup(struct inode *dir,
|
||||
struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct configfs_dirent * parent_sd = dentry->d_parent->d_fsdata;
|
||||
struct configfs_dirent * sd;
|
||||
|
|
|
@ -417,7 +417,7 @@ static int cramfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
|
|||
/*
|
||||
* Lookup and fill in the inode data..
|
||||
*/
|
||||
static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
static struct dentry * cramfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
unsigned int offset = 0;
|
||||
struct inode *inode = NULL;
|
||||
|
|
44
fs/dcache.c
44
fs/dcache.c
|
@ -218,7 +218,7 @@ static void __d_free(struct rcu_head *head)
|
|||
{
|
||||
struct dentry *dentry = container_of(head, struct dentry, d_u.d_rcu);
|
||||
|
||||
WARN_ON(!list_empty(&dentry->d_alias));
|
||||
WARN_ON(!hlist_unhashed(&dentry->d_alias));
|
||||
if (dname_external(dentry))
|
||||
kfree(dentry->d_name.name);
|
||||
kmem_cache_free(dentry_cache, dentry);
|
||||
|
@ -267,7 +267,7 @@ static void dentry_iput(struct dentry * dentry)
|
|||
struct inode *inode = dentry->d_inode;
|
||||
if (inode) {
|
||||
dentry->d_inode = NULL;
|
||||
list_del_init(&dentry->d_alias);
|
||||
hlist_del_init(&dentry->d_alias);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (!inode->i_nlink)
|
||||
|
@ -291,7 +291,7 @@ static void dentry_unlink_inode(struct dentry * dentry)
|
|||
{
|
||||
struct inode *inode = dentry->d_inode;
|
||||
dentry->d_inode = NULL;
|
||||
list_del_init(&dentry->d_alias);
|
||||
hlist_del_init(&dentry->d_alias);
|
||||
dentry_rcuwalk_barrier(dentry);
|
||||
spin_unlock(&dentry->d_lock);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
@ -699,10 +699,11 @@ EXPORT_SYMBOL(dget_parent);
|
|||
static struct dentry *__d_find_alias(struct inode *inode, int want_discon)
|
||||
{
|
||||
struct dentry *alias, *discon_alias;
|
||||
struct hlist_node *p;
|
||||
|
||||
again:
|
||||
discon_alias = NULL;
|
||||
list_for_each_entry(alias, &inode->i_dentry, d_alias) {
|
||||
hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
|
||||
spin_lock(&alias->d_lock);
|
||||
if (S_ISDIR(inode->i_mode) || !d_unhashed(alias)) {
|
||||
if (IS_ROOT(alias) &&
|
||||
|
@ -737,7 +738,7 @@ struct dentry *d_find_alias(struct inode *inode)
|
|||
{
|
||||
struct dentry *de = NULL;
|
||||
|
||||
if (!list_empty(&inode->i_dentry)) {
|
||||
if (!hlist_empty(&inode->i_dentry)) {
|
||||
spin_lock(&inode->i_lock);
|
||||
de = __d_find_alias(inode, 0);
|
||||
spin_unlock(&inode->i_lock);
|
||||
|
@ -753,9 +754,10 @@ EXPORT_SYMBOL(d_find_alias);
|
|||
void d_prune_aliases(struct inode *inode)
|
||||
{
|
||||
struct dentry *dentry;
|
||||
struct hlist_node *p;
|
||||
restart:
|
||||
spin_lock(&inode->i_lock);
|
||||
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
|
||||
hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
|
||||
spin_lock(&dentry->d_lock);
|
||||
if (!dentry->d_count) {
|
||||
__dget_dlock(dentry);
|
||||
|
@ -977,7 +979,7 @@ static void shrink_dcache_for_umount_subtree(struct dentry *dentry)
|
|||
inode = dentry->d_inode;
|
||||
if (inode) {
|
||||
dentry->d_inode = NULL;
|
||||
list_del_init(&dentry->d_alias);
|
||||
hlist_del_init(&dentry->d_alias);
|
||||
if (dentry->d_op && dentry->d_op->d_iput)
|
||||
dentry->d_op->d_iput(dentry, inode);
|
||||
else
|
||||
|
@ -1312,7 +1314,7 @@ struct dentry *__d_alloc(struct super_block *sb, const struct qstr *name)
|
|||
INIT_HLIST_BL_NODE(&dentry->d_hash);
|
||||
INIT_LIST_HEAD(&dentry->d_lru);
|
||||
INIT_LIST_HEAD(&dentry->d_subdirs);
|
||||
INIT_LIST_HEAD(&dentry->d_alias);
|
||||
INIT_HLIST_NODE(&dentry->d_alias);
|
||||
INIT_LIST_HEAD(&dentry->d_u.d_child);
|
||||
d_set_d_op(dentry, dentry->d_sb->s_d_op);
|
||||
|
||||
|
@ -1400,7 +1402,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
|
|||
if (inode) {
|
||||
if (unlikely(IS_AUTOMOUNT(inode)))
|
||||
dentry->d_flags |= DCACHE_NEED_AUTOMOUNT;
|
||||
list_add(&dentry->d_alias, &inode->i_dentry);
|
||||
hlist_add_head(&dentry->d_alias, &inode->i_dentry);
|
||||
}
|
||||
dentry->d_inode = inode;
|
||||
dentry_rcuwalk_barrier(dentry);
|
||||
|
@ -1425,7 +1427,7 @@ static void __d_instantiate(struct dentry *dentry, struct inode *inode)
|
|||
|
||||
void d_instantiate(struct dentry *entry, struct inode * inode)
|
||||
{
|
||||
BUG_ON(!list_empty(&entry->d_alias));
|
||||
BUG_ON(!hlist_unhashed(&entry->d_alias));
|
||||
if (inode)
|
||||
spin_lock(&inode->i_lock);
|
||||
__d_instantiate(entry, inode);
|
||||
|
@ -1458,13 +1460,14 @@ static struct dentry *__d_instantiate_unique(struct dentry *entry,
|
|||
int len = entry->d_name.len;
|
||||
const char *name = entry->d_name.name;
|
||||
unsigned int hash = entry->d_name.hash;
|
||||
struct hlist_node *p;
|
||||
|
||||
if (!inode) {
|
||||
__d_instantiate(entry, NULL);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
list_for_each_entry(alias, &inode->i_dentry, d_alias) {
|
||||
hlist_for_each_entry(alias, p, &inode->i_dentry, d_alias) {
|
||||
/*
|
||||
* Don't need alias->d_lock here, because aliases with
|
||||
* d_parent == entry->d_parent are not subject to name or
|
||||
|
@ -1490,7 +1493,7 @@ struct dentry *d_instantiate_unique(struct dentry *entry, struct inode *inode)
|
|||
{
|
||||
struct dentry *result;
|
||||
|
||||
BUG_ON(!list_empty(&entry->d_alias));
|
||||
BUG_ON(!hlist_unhashed(&entry->d_alias));
|
||||
|
||||
if (inode)
|
||||
spin_lock(&inode->i_lock);
|
||||
|
@ -1531,9 +1534,9 @@ static struct dentry * __d_find_any_alias(struct inode *inode)
|
|||
{
|
||||
struct dentry *alias;
|
||||
|
||||
if (list_empty(&inode->i_dentry))
|
||||
if (hlist_empty(&inode->i_dentry))
|
||||
return NULL;
|
||||
alias = list_first_entry(&inode->i_dentry, struct dentry, d_alias);
|
||||
alias = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
|
||||
__dget(alias);
|
||||
return alias;
|
||||
}
|
||||
|
@ -1607,7 +1610,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
|
|||
spin_lock(&tmp->d_lock);
|
||||
tmp->d_inode = inode;
|
||||
tmp->d_flags |= DCACHE_DISCONNECTED;
|
||||
list_add(&tmp->d_alias, &inode->i_dentry);
|
||||
hlist_add_head(&tmp->d_alias, &inode->i_dentry);
|
||||
hlist_bl_lock(&tmp->d_sb->s_anon);
|
||||
hlist_bl_add_head(&tmp->d_hash, &tmp->d_sb->s_anon);
|
||||
hlist_bl_unlock(&tmp->d_sb->s_anon);
|
||||
|
@ -2384,14 +2387,13 @@ static struct dentry *__d_unalias(struct inode *inode,
|
|||
struct dentry *dentry, struct dentry *alias)
|
||||
{
|
||||
struct mutex *m1 = NULL, *m2 = NULL;
|
||||
struct dentry *ret;
|
||||
struct dentry *ret = ERR_PTR(-EBUSY);
|
||||
|
||||
/* If alias and dentry share a parent, then no extra locks required */
|
||||
if (alias->d_parent == dentry->d_parent)
|
||||
goto out_unalias;
|
||||
|
||||
/* See lock_rename() */
|
||||
ret = ERR_PTR(-EBUSY);
|
||||
if (!mutex_trylock(&dentry->d_sb->s_vfs_rename_mutex))
|
||||
goto out_err;
|
||||
m1 = &dentry->d_sb->s_vfs_rename_mutex;
|
||||
|
@ -2399,8 +2401,10 @@ static struct dentry *__d_unalias(struct inode *inode,
|
|||
goto out_err;
|
||||
m2 = &alias->d_parent->d_inode->i_mutex;
|
||||
out_unalias:
|
||||
__d_move(alias, dentry);
|
||||
ret = alias;
|
||||
if (likely(!d_mountpoint(alias))) {
|
||||
__d_move(alias, dentry);
|
||||
ret = alias;
|
||||
}
|
||||
out_err:
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (m2)
|
||||
|
@ -2622,7 +2626,7 @@ global_root:
|
|||
if (!slash)
|
||||
error = prepend(buffer, buflen, "/", 1);
|
||||
if (!error)
|
||||
error = real_mount(vfsmnt)->mnt_ns ? 1 : 2;
|
||||
error = is_mounted(vfsmnt) ? 1 : 2;
|
||||
goto out;
|
||||
}
|
||||
|
||||
|
|
|
@ -54,13 +54,12 @@ static struct inode *debugfs_get_inode(struct super_block *sb, umode_t mode, dev
|
|||
break;
|
||||
case S_IFLNK:
|
||||
inode->i_op = &debugfs_link_operations;
|
||||
inode->i_fop = fops;
|
||||
inode->i_private = data;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
inode->i_op = &simple_dir_inode_operations;
|
||||
inode->i_fop = fops ? fops : &simple_dir_operations;
|
||||
inode->i_private = data;
|
||||
inode->i_fop = &simple_dir_operations;
|
||||
inode->i_private = NULL;
|
||||
|
||||
/* directory inodes start off with i_nlink == 2
|
||||
* (for "." entry) */
|
||||
|
@ -91,13 +90,12 @@ static int debugfs_mknod(struct inode *dir, struct dentry *dentry,
|
|||
return error;
|
||||
}
|
||||
|
||||
static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
void *data, const struct file_operations *fops)
|
||||
static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
|
||||
{
|
||||
int res;
|
||||
|
||||
mode = (mode & (S_IRWXUGO | S_ISVTX)) | S_IFDIR;
|
||||
res = debugfs_mknod(dir, dentry, mode, 0, data, fops);
|
||||
res = debugfs_mknod(dir, dentry, mode, 0, NULL, NULL);
|
||||
if (!res) {
|
||||
inc_nlink(dir);
|
||||
fsnotify_mkdir(dir, dentry);
|
||||
|
@ -106,10 +104,10 @@ static int debugfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
}
|
||||
|
||||
static int debugfs_link(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
void *data, const struct file_operations *fops)
|
||||
void *data)
|
||||
{
|
||||
mode = (mode & S_IALLUGO) | S_IFLNK;
|
||||
return debugfs_mknod(dir, dentry, mode, 0, data, fops);
|
||||
return debugfs_mknod(dir, dentry, mode, 0, data, NULL);
|
||||
}
|
||||
|
||||
static int debugfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
|
@ -293,13 +291,19 @@ static struct file_system_type debug_fs_type = {
|
|||
.kill_sb = kill_litter_super,
|
||||
};
|
||||
|
||||
static int debugfs_create_by_name(const char *name, umode_t mode,
|
||||
struct dentry *parent,
|
||||
struct dentry **dentry,
|
||||
void *data,
|
||||
const struct file_operations *fops)
|
||||
struct dentry *__create_file(const char *name, umode_t mode,
|
||||
struct dentry *parent, void *data,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
int error = 0;
|
||||
struct dentry *dentry = NULL;
|
||||
int error;
|
||||
|
||||
pr_debug("debugfs: creating file '%s'\n",name);
|
||||
|
||||
error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
|
||||
&debugfs_mount_count);
|
||||
if (error)
|
||||
goto exit;
|
||||
|
||||
/* If the parent is not specified, we create it in the root.
|
||||
* We need the root dentry to do this, which is in the super
|
||||
|
@ -309,30 +313,35 @@ static int debugfs_create_by_name(const char *name, umode_t mode,
|
|||
if (!parent)
|
||||
parent = debugfs_mount->mnt_root;
|
||||
|
||||
*dentry = NULL;
|
||||
dentry = NULL;
|
||||
mutex_lock(&parent->d_inode->i_mutex);
|
||||
*dentry = lookup_one_len(name, parent, strlen(name));
|
||||
if (!IS_ERR(*dentry)) {
|
||||
dentry = lookup_one_len(name, parent, strlen(name));
|
||||
if (!IS_ERR(dentry)) {
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFDIR:
|
||||
error = debugfs_mkdir(parent->d_inode, *dentry, mode,
|
||||
data, fops);
|
||||
error = debugfs_mkdir(parent->d_inode, dentry, mode);
|
||||
|
||||
break;
|
||||
case S_IFLNK:
|
||||
error = debugfs_link(parent->d_inode, *dentry, mode,
|
||||
data, fops);
|
||||
error = debugfs_link(parent->d_inode, dentry, mode,
|
||||
data);
|
||||
break;
|
||||
default:
|
||||
error = debugfs_create(parent->d_inode, *dentry, mode,
|
||||
error = debugfs_create(parent->d_inode, dentry, mode,
|
||||
data, fops);
|
||||
break;
|
||||
}
|
||||
dput(*dentry);
|
||||
dput(dentry);
|
||||
} else
|
||||
error = PTR_ERR(*dentry);
|
||||
error = PTR_ERR(dentry);
|
||||
mutex_unlock(&parent->d_inode->i_mutex);
|
||||
|
||||
return error;
|
||||
if (error) {
|
||||
dentry = NULL;
|
||||
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
||||
}
|
||||
exit:
|
||||
return dentry;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -365,25 +374,15 @@ struct dentry *debugfs_create_file(const char *name, umode_t mode,
|
|||
struct dentry *parent, void *data,
|
||||
const struct file_operations *fops)
|
||||
{
|
||||
struct dentry *dentry = NULL;
|
||||
int error;
|
||||
|
||||
pr_debug("debugfs: creating file '%s'\n",name);
|
||||
|
||||
error = simple_pin_fs(&debug_fs_type, &debugfs_mount,
|
||||
&debugfs_mount_count);
|
||||
if (error)
|
||||
goto exit;
|
||||
|
||||
error = debugfs_create_by_name(name, mode, parent, &dentry,
|
||||
data, fops);
|
||||
if (error) {
|
||||
dentry = NULL;
|
||||
simple_release_fs(&debugfs_mount, &debugfs_mount_count);
|
||||
goto exit;
|
||||
switch (mode & S_IFMT) {
|
||||
case S_IFREG:
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
BUG();
|
||||
}
|
||||
exit:
|
||||
return dentry;
|
||||
|
||||
return __create_file(name, mode, parent, data, fops);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_file);
|
||||
|
||||
|
@ -407,8 +406,7 @@ EXPORT_SYMBOL_GPL(debugfs_create_file);
|
|||
*/
|
||||
struct dentry *debugfs_create_dir(const char *name, struct dentry *parent)
|
||||
{
|
||||
return debugfs_create_file(name,
|
||||
S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
|
||||
return __create_file(name, S_IFDIR | S_IRWXU | S_IRUGO | S_IXUGO,
|
||||
parent, NULL, NULL);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(debugfs_create_dir);
|
||||
|
@ -446,8 +444,7 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
|||
if (!link)
|
||||
return NULL;
|
||||
|
||||
result = debugfs_create_file(name, S_IFLNK | S_IRWXUGO, parent, link,
|
||||
NULL);
|
||||
result = __create_file(name, S_IFLNK | S_IRWXUGO, parent, link, NULL);
|
||||
if (!result)
|
||||
kfree(link);
|
||||
return result;
|
||||
|
|
|
@ -439,15 +439,15 @@ static struct dentry *devpts_mount(struct file_system_type *fs_type,
|
|||
return ERR_PTR(error);
|
||||
|
||||
if (opts.newinstance)
|
||||
s = sget(fs_type, NULL, set_anon_super, NULL);
|
||||
s = sget(fs_type, NULL, set_anon_super, flags, NULL);
|
||||
else
|
||||
s = sget(fs_type, compare_init_pts_sb, set_anon_super, NULL);
|
||||
s = sget(fs_type, compare_init_pts_sb, set_anon_super, flags,
|
||||
NULL);
|
||||
|
||||
if (IS_ERR(s))
|
||||
return ERR_CAST(s);
|
||||
|
||||
if (!s->s_root) {
|
||||
s->s_flags = flags;
|
||||
error = devpts_fill_super(s, data, flags & MS_SILENT ? 1 : 0);
|
||||
if (error)
|
||||
goto out_undo_sget;
|
||||
|
|
|
@ -1258,7 +1258,7 @@ do_blockdev_direct_IO(int rw, struct kiocb *iocb, struct inode *inode,
|
|||
*/
|
||||
BUG_ON(retval == -EIOCBQUEUED);
|
||||
if (dio->is_async && retval == 0 && dio->result &&
|
||||
((rw & READ) || (dio->result == sdio.size)))
|
||||
((rw == READ) || (dio->result == sdio.size)))
|
||||
retval = -EIOCBQUEUED;
|
||||
|
||||
if (retval != -EIOCBQUEUED)
|
||||
|
|
|
@ -32,7 +32,7 @@
|
|||
/**
|
||||
* ecryptfs_d_revalidate - revalidate an ecryptfs dentry
|
||||
* @dentry: The ecryptfs dentry
|
||||
* @nd: The associated nameidata
|
||||
* @flags: lookup flags
|
||||
*
|
||||
* Called when the VFS needs to revalidate a dentry. This
|
||||
* is called whenever a name lookup finds a dentry in the
|
||||
|
@ -42,32 +42,20 @@
|
|||
* Returns 1 if valid, 0 otherwise.
|
||||
*
|
||||
*/
|
||||
static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
static int ecryptfs_d_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct dentry *lower_dentry;
|
||||
struct vfsmount *lower_mnt;
|
||||
struct dentry *dentry_save = NULL;
|
||||
struct vfsmount *vfsmount_save = NULL;
|
||||
int rc = 1;
|
||||
|
||||
if (nd && nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
lower_dentry = ecryptfs_dentry_to_lower(dentry);
|
||||
lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);
|
||||
if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)
|
||||
goto out;
|
||||
if (nd) {
|
||||
dentry_save = nd->path.dentry;
|
||||
vfsmount_save = nd->path.mnt;
|
||||
nd->path.dentry = lower_dentry;
|
||||
nd->path.mnt = lower_mnt;
|
||||
}
|
||||
rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);
|
||||
if (nd) {
|
||||
nd->path.dentry = dentry_save;
|
||||
nd->path.mnt = vfsmount_save;
|
||||
}
|
||||
rc = lower_dentry->d_op->d_revalidate(lower_dentry, flags);
|
||||
if (dentry->d_inode) {
|
||||
struct inode *lower_inode =
|
||||
ecryptfs_inode_to_lower(dentry->d_inode);
|
||||
|
|
|
@ -550,20 +550,6 @@ extern struct kmem_cache *ecryptfs_key_record_cache;
|
|||
extern struct kmem_cache *ecryptfs_key_sig_cache;
|
||||
extern struct kmem_cache *ecryptfs_global_auth_tok_cache;
|
||||
extern struct kmem_cache *ecryptfs_key_tfm_cache;
|
||||
extern struct kmem_cache *ecryptfs_open_req_cache;
|
||||
|
||||
struct ecryptfs_open_req {
|
||||
#define ECRYPTFS_REQ_PROCESSED 0x00000001
|
||||
#define ECRYPTFS_REQ_DROPPED 0x00000002
|
||||
#define ECRYPTFS_REQ_ZOMBIE 0x00000004
|
||||
u32 flags;
|
||||
struct file **lower_file;
|
||||
struct dentry *lower_dentry;
|
||||
struct vfsmount *lower_mnt;
|
||||
wait_queue_head_t wait;
|
||||
struct mutex mux;
|
||||
struct list_head kthread_ctl_list;
|
||||
};
|
||||
|
||||
struct inode *ecryptfs_get_inode(struct inode *lower_inode,
|
||||
struct super_block *sb);
|
||||
|
|
|
@ -173,7 +173,7 @@ ecryptfs_do_create(struct inode *directory_inode,
|
|||
inode = ERR_CAST(lower_dir_dentry);
|
||||
goto out;
|
||||
}
|
||||
rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, NULL);
|
||||
rc = vfs_create(lower_dir_dentry->d_inode, lower_dentry, mode, true);
|
||||
if (rc) {
|
||||
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
|
||||
"rc = [%d]\n", __func__, rc);
|
||||
|
@ -240,7 +240,6 @@ out:
|
|||
* @dir: The inode of the directory in which to create the file.
|
||||
* @dentry: The eCryptfs dentry
|
||||
* @mode: The mode of the new file.
|
||||
* @nd: nameidata
|
||||
*
|
||||
* Creates a new file.
|
||||
*
|
||||
|
@ -248,7 +247,7 @@ out:
|
|||
*/
|
||||
static int
|
||||
ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
|
||||
umode_t mode, struct nameidata *nd)
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
struct inode *ecryptfs_inode;
|
||||
int rc;
|
||||
|
@ -270,8 +269,8 @@ ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,
|
|||
iput(ecryptfs_inode);
|
||||
goto out;
|
||||
}
|
||||
d_instantiate(ecryptfs_dentry, ecryptfs_inode);
|
||||
unlock_new_inode(ecryptfs_inode);
|
||||
d_instantiate(ecryptfs_dentry, ecryptfs_inode);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
@ -374,7 +373,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,
|
|||
*/
|
||||
static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,
|
||||
struct dentry *ecryptfs_dentry,
|
||||
struct nameidata *ecryptfs_nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
char *encrypted_and_encoded_name = NULL;
|
||||
size_t encrypted_and_encoded_name_size;
|
||||
|
|
|
@ -27,7 +27,12 @@
|
|||
#include <linux/mount.h>
|
||||
#include "ecryptfs_kernel.h"
|
||||
|
||||
struct kmem_cache *ecryptfs_open_req_cache;
|
||||
struct ecryptfs_open_req {
|
||||
struct file **lower_file;
|
||||
struct path path;
|
||||
struct completion done;
|
||||
struct list_head kthread_ctl_list;
|
||||
};
|
||||
|
||||
static struct ecryptfs_kthread_ctl {
|
||||
#define ECRYPTFS_KTHREAD_ZOMBIE 0x00000001
|
||||
|
@ -67,18 +72,10 @@ static int ecryptfs_threadfn(void *ignored)
|
|||
req = list_first_entry(&ecryptfs_kthread_ctl.req_list,
|
||||
struct ecryptfs_open_req,
|
||||
kthread_ctl_list);
|
||||
mutex_lock(&req->mux);
|
||||
list_del(&req->kthread_ctl_list);
|
||||
if (!(req->flags & ECRYPTFS_REQ_ZOMBIE)) {
|
||||
dget(req->lower_dentry);
|
||||
mntget(req->lower_mnt);
|
||||
(*req->lower_file) = dentry_open(
|
||||
req->lower_dentry, req->lower_mnt,
|
||||
(O_RDWR | O_LARGEFILE), current_cred());
|
||||
req->flags |= ECRYPTFS_REQ_PROCESSED;
|
||||
}
|
||||
wake_up(&req->wait);
|
||||
mutex_unlock(&req->mux);
|
||||
*req->lower_file = dentry_open(&req->path,
|
||||
(O_RDWR | O_LARGEFILE), current_cred());
|
||||
complete(&req->done);
|
||||
}
|
||||
mutex_unlock(&ecryptfs_kthread_ctl.mux);
|
||||
}
|
||||
|
@ -111,10 +108,9 @@ void ecryptfs_destroy_kthread(void)
|
|||
ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;
|
||||
list_for_each_entry(req, &ecryptfs_kthread_ctl.req_list,
|
||||
kthread_ctl_list) {
|
||||
mutex_lock(&req->mux);
|
||||
req->flags |= ECRYPTFS_REQ_ZOMBIE;
|
||||
wake_up(&req->wait);
|
||||
mutex_unlock(&req->mux);
|
||||
list_del(&req->kthread_ctl_list);
|
||||
*req->lower_file = ERR_PTR(-EIO);
|
||||
complete(&req->done);
|
||||
}
|
||||
mutex_unlock(&ecryptfs_kthread_ctl.mux);
|
||||
kthread_stop(ecryptfs_kthread);
|
||||
|
@ -136,34 +132,26 @@ int ecryptfs_privileged_open(struct file **lower_file,
|
|||
struct vfsmount *lower_mnt,
|
||||
const struct cred *cred)
|
||||
{
|
||||
struct ecryptfs_open_req *req;
|
||||
struct ecryptfs_open_req req;
|
||||
int flags = O_LARGEFILE;
|
||||
int rc = 0;
|
||||
|
||||
init_completion(&req.done);
|
||||
req.lower_file = lower_file;
|
||||
req.path.dentry = lower_dentry;
|
||||
req.path.mnt = lower_mnt;
|
||||
|
||||
/* Corresponding dput() and mntput() are done when the
|
||||
* lower file is fput() when all eCryptfs files for the inode are
|
||||
* released. */
|
||||
dget(lower_dentry);
|
||||
mntget(lower_mnt);
|
||||
flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;
|
||||
(*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);
|
||||
(*lower_file) = dentry_open(&req.path, flags, cred);
|
||||
if (!IS_ERR(*lower_file))
|
||||
goto out;
|
||||
if ((flags & O_ACCMODE) == O_RDONLY) {
|
||||
rc = PTR_ERR((*lower_file));
|
||||
goto out;
|
||||
}
|
||||
req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);
|
||||
if (!req) {
|
||||
rc = -ENOMEM;
|
||||
goto out;
|
||||
}
|
||||
mutex_init(&req->mux);
|
||||
req->lower_file = lower_file;
|
||||
req->lower_dentry = lower_dentry;
|
||||
req->lower_mnt = lower_mnt;
|
||||
init_waitqueue_head(&req->wait);
|
||||
req->flags = 0;
|
||||
mutex_lock(&ecryptfs_kthread_ctl.mux);
|
||||
if (ecryptfs_kthread_ctl.flags & ECRYPTFS_KTHREAD_ZOMBIE) {
|
||||
rc = -EIO;
|
||||
|
@ -171,27 +159,14 @@ int ecryptfs_privileged_open(struct file **lower_file,
|
|||
printk(KERN_ERR "%s: We are in the middle of shutting down; "
|
||||
"aborting privileged request to open lower file\n",
|
||||
__func__);
|
||||
goto out_free;
|
||||
goto out;
|
||||
}
|
||||
list_add_tail(&req->kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
|
||||
list_add_tail(&req.kthread_ctl_list, &ecryptfs_kthread_ctl.req_list);
|
||||
mutex_unlock(&ecryptfs_kthread_ctl.mux);
|
||||
wake_up(&ecryptfs_kthread_ctl.wait);
|
||||
wait_event(req->wait, (req->flags != 0));
|
||||
mutex_lock(&req->mux);
|
||||
BUG_ON(req->flags == 0);
|
||||
if (req->flags & ECRYPTFS_REQ_DROPPED
|
||||
|| req->flags & ECRYPTFS_REQ_ZOMBIE) {
|
||||
rc = -EIO;
|
||||
printk(KERN_WARNING "%s: Privileged open request dropped\n",
|
||||
__func__);
|
||||
goto out_unlock;
|
||||
}
|
||||
if (IS_ERR(*req->lower_file))
|
||||
rc = PTR_ERR(*req->lower_file);
|
||||
out_unlock:
|
||||
mutex_unlock(&req->mux);
|
||||
out_free:
|
||||
kmem_cache_free(ecryptfs_open_req_cache, req);
|
||||
wait_for_completion(&req.done);
|
||||
if (IS_ERR(*lower_file))
|
||||
rc = PTR_ERR(*lower_file);
|
||||
out:
|
||||
return rc;
|
||||
}
|
||||
|
|
|
@ -499,13 +499,12 @@ static struct dentry *ecryptfs_mount(struct file_system_type *fs_type, int flags
|
|||
goto out;
|
||||
}
|
||||
|
||||
s = sget(fs_type, NULL, set_anon_super, NULL);
|
||||
s = sget(fs_type, NULL, set_anon_super, flags, NULL);
|
||||
if (IS_ERR(s)) {
|
||||
rc = PTR_ERR(s);
|
||||
goto out;
|
||||
}
|
||||
|
||||
s->s_flags = flags;
|
||||
rc = bdi_setup_and_register(&sbi->bdi, "ecryptfs", BDI_CAP_MAP_COPY);
|
||||
if (rc)
|
||||
goto out1;
|
||||
|
@ -682,11 +681,6 @@ static struct ecryptfs_cache_info {
|
|||
.name = "ecryptfs_key_tfm_cache",
|
||||
.size = sizeof(struct ecryptfs_key_tfm),
|
||||
},
|
||||
{
|
||||
.cache = &ecryptfs_open_req_cache,
|
||||
.name = "ecryptfs_open_req_cache",
|
||||
.size = sizeof(struct ecryptfs_open_req),
|
||||
},
|
||||
};
|
||||
|
||||
static void ecryptfs_free_kmem_caches(void)
|
||||
|
|
|
@ -129,7 +129,7 @@ extern struct inode *efs_iget(struct super_block *, unsigned long);
|
|||
extern efs_block_t efs_map_block(struct inode *, efs_block_t);
|
||||
extern int efs_get_block(struct inode *, sector_t, struct buffer_head *, int);
|
||||
|
||||
extern struct dentry *efs_lookup(struct inode *, struct dentry *, struct nameidata *);
|
||||
extern struct dentry *efs_lookup(struct inode *, struct dentry *, unsigned int);
|
||||
extern struct dentry *efs_fh_to_dentry(struct super_block *sb, struct fid *fid,
|
||||
int fh_len, int fh_type);
|
||||
extern struct dentry *efs_fh_to_parent(struct super_block *sb, struct fid *fid,
|
||||
|
|
|
@ -58,7 +58,8 @@ static efs_ino_t efs_find_entry(struct inode *inode, const char *name, int len)
|
|||
return(0);
|
||||
}
|
||||
|
||||
struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) {
|
||||
struct dentry *efs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
efs_ino_t inodenum;
|
||||
struct inode *inode = NULL;
|
||||
|
||||
|
|
|
@ -46,7 +46,7 @@ static inline int exofs_add_nondir(struct dentry *dentry, struct inode *inode)
|
|||
}
|
||||
|
||||
static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
ino_t ino;
|
||||
|
@ -60,7 +60,7 @@ static struct dentry *exofs_lookup(struct inode *dir, struct dentry *dentry,
|
|||
}
|
||||
|
||||
static int exofs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
struct inode *inode = exofs_new_inode(dir, mode);
|
||||
int err = PTR_ERR(inode);
|
||||
|
|
|
@ -19,19 +19,19 @@
|
|||
#define dprintk(fmt, args...) do{}while(0)
|
||||
|
||||
|
||||
static int get_name(struct vfsmount *mnt, struct dentry *dentry, char *name,
|
||||
struct dentry *child);
|
||||
static int get_name(const struct path *path, char *name, struct dentry *child);
|
||||
|
||||
|
||||
static int exportfs_get_name(struct vfsmount *mnt, struct dentry *dir,
|
||||
char *name, struct dentry *child)
|
||||
{
|
||||
const struct export_operations *nop = dir->d_sb->s_export_op;
|
||||
struct path path = {.mnt = mnt, .dentry = dir};
|
||||
|
||||
if (nop->get_name)
|
||||
return nop->get_name(dir, name, child);
|
||||
else
|
||||
return get_name(mnt, dir, name, child);
|
||||
return get_name(&path, name, child);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -44,13 +44,14 @@ find_acceptable_alias(struct dentry *result,
|
|||
{
|
||||
struct dentry *dentry, *toput = NULL;
|
||||
struct inode *inode;
|
||||
struct hlist_node *p;
|
||||
|
||||
if (acceptable(context, result))
|
||||
return result;
|
||||
|
||||
inode = result->d_inode;
|
||||
spin_lock(&inode->i_lock);
|
||||
list_for_each_entry(dentry, &inode->i_dentry, d_alias) {
|
||||
hlist_for_each_entry(dentry, p, &inode->i_dentry, d_alias) {
|
||||
dget(dentry);
|
||||
spin_unlock(&inode->i_lock);
|
||||
if (toput)
|
||||
|
@ -248,11 +249,10 @@ static int filldir_one(void * __buf, const char * name, int len,
|
|||
* calls readdir on the parent until it finds an entry with
|
||||
* the same inode number as the child, and returns that.
|
||||
*/
|
||||
static int get_name(struct vfsmount *mnt, struct dentry *dentry,
|
||||
char *name, struct dentry *child)
|
||||
static int get_name(const struct path *path, char *name, struct dentry *child)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct inode *dir = dentry->d_inode;
|
||||
struct inode *dir = path->dentry->d_inode;
|
||||
int error;
|
||||
struct file *file;
|
||||
struct getdents_callback buffer;
|
||||
|
@ -266,7 +266,7 @@ static int get_name(struct vfsmount *mnt, struct dentry *dentry,
|
|||
/*
|
||||
* Open the directory ...
|
||||
*/
|
||||
file = dentry_open(dget(dentry), mntget(mnt), O_RDONLY, cred);
|
||||
file = dentry_open(path, O_RDONLY, cred);
|
||||
error = PTR_ERR(file);
|
||||
if (IS_ERR(file))
|
||||
goto out;
|
||||
|
|
|
@ -41,8 +41,8 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
|
|||
{
|
||||
int err = ext2_add_link(dentry, inode);
|
||||
if (!err) {
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
}
|
||||
inode_dec_link_count(inode);
|
||||
|
@ -55,7 +55,7 @@ static inline int ext2_add_nondir(struct dentry *dentry, struct inode *inode)
|
|||
* Methods themselves.
|
||||
*/
|
||||
|
||||
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
|
||||
static struct dentry *ext2_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode * inode;
|
||||
ino_t ino;
|
||||
|
@ -94,7 +94,7 @@ struct dentry *ext2_get_parent(struct dentry *child)
|
|||
* If the create succeeds, we fill in the inode information
|
||||
* with d_instantiate().
|
||||
*/
|
||||
static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, struct nameidata *nd)
|
||||
static int ext2_create (struct inode * dir, struct dentry * dentry, umode_t mode, bool excl)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
|
@ -242,8 +242,8 @@ static int ext2_mkdir(struct inode * dir, struct dentry * dentry, umode_t mode)
|
|||
if (err)
|
||||
goto out_fail;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
out:
|
||||
return err;
|
||||
|
||||
|
|
|
@ -1184,6 +1184,12 @@ static int ext2_sync_fs(struct super_block *sb, int wait)
|
|||
struct ext2_sb_info *sbi = EXT2_SB(sb);
|
||||
struct ext2_super_block *es = EXT2_SB(sb)->s_es;
|
||||
|
||||
/*
|
||||
* Write quota structures to quota file, sync_blockdev() will write
|
||||
* them to disk later
|
||||
*/
|
||||
dquot_writeback_dquots(sb, -1);
|
||||
|
||||
spin_lock(&sbi->s_lock);
|
||||
if (es->s_state & cpu_to_le16(EXT2_VALID_FS)) {
|
||||
ext2_debug("setting valid to 0\n");
|
||||
|
|
|
@ -300,10 +300,11 @@ loff_t ext3_dir_llseek(struct file *file, loff_t offset, int origin)
|
|||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
int dx_dir = is_dx_dir(inode);
|
||||
loff_t htree_max = ext3_get_htree_eof(file);
|
||||
|
||||
if (likely(dx_dir))
|
||||
return generic_file_llseek_size(file, offset, origin,
|
||||
ext3_get_htree_eof(file));
|
||||
htree_max, htree_max);
|
||||
else
|
||||
return generic_file_llseek(file, offset, origin);
|
||||
}
|
||||
|
|
|
@ -1011,7 +1011,7 @@ errout:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, struct nameidata *nd)
|
||||
static struct dentry *ext3_lookup(struct inode * dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode * inode;
|
||||
struct ext3_dir_entry_2 * de;
|
||||
|
@ -1671,8 +1671,8 @@ static int ext3_add_nondir(handle_t *handle,
|
|||
int err = ext3_add_entry(handle, dentry, inode);
|
||||
if (!err) {
|
||||
ext3_mark_inode_dirty(handle, inode);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
}
|
||||
drop_nlink(inode);
|
||||
|
@ -1690,7 +1690,7 @@ static int ext3_add_nondir(handle_t *handle,
|
|||
* with d_instantiate().
|
||||
*/
|
||||
static int ext3_create (struct inode * dir, struct dentry * dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
handle_t *handle;
|
||||
struct inode * inode;
|
||||
|
@ -1836,8 +1836,8 @@ out_clear_inode:
|
|||
if (err)
|
||||
goto out_clear_inode;
|
||||
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
out_stop:
|
||||
brelse(dir_block);
|
||||
ext3_journal_stop(handle);
|
||||
|
|
|
@ -2526,6 +2526,11 @@ static int ext3_sync_fs(struct super_block *sb, int wait)
|
|||
tid_t target;
|
||||
|
||||
trace_ext3_sync_fs(sb, wait);
|
||||
/*
|
||||
* Writeback quota in non-journalled quota case - journalled quota has
|
||||
* no dirty dquots
|
||||
*/
|
||||
dquot_writeback_dquots(sb, -1);
|
||||
if (journal_start_commit(EXT3_SB(sb)->s_journal, &target)) {
|
||||
if (wait)
|
||||
log_wait_commit(EXT3_SB(sb)->s_journal, target);
|
||||
|
|
|
@ -324,74 +324,27 @@ static inline loff_t ext4_get_htree_eof(struct file *filp)
|
|||
|
||||
|
||||
/*
|
||||
* ext4_dir_llseek() based on generic_file_llseek() to handle both
|
||||
* non-htree and htree directories, where the "offset" is in terms
|
||||
* of the filename hash value instead of the byte offset.
|
||||
* ext4_dir_llseek() calls generic_file_llseek_size to handle htree
|
||||
* directories, where the "offset" is in terms of the filename hash
|
||||
* value instead of the byte offset.
|
||||
*
|
||||
* NOTE: offsets obtained *before* ext4_set_inode_flag(dir, EXT4_INODE_INDEX)
|
||||
* will be invalid once the directory was converted into a dx directory
|
||||
* Because we may return a 64-bit hash that is well beyond offset limits,
|
||||
* we need to pass the max hash as the maximum allowable offset in
|
||||
* the htree directory case.
|
||||
*
|
||||
* For non-htree, ext4_llseek already chooses the proper max offset.
|
||||
*/
|
||||
loff_t ext4_dir_llseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
loff_t ret = -EINVAL;
|
||||
int dx_dir = is_dx_dir(inode);
|
||||
loff_t htree_max = ext4_get_htree_eof(file);
|
||||
|
||||
mutex_lock(&inode->i_mutex);
|
||||
|
||||
/* NOTE: relative offsets with dx directories might not work
|
||||
* as expected, as it is difficult to figure out the
|
||||
* correct offset between dx hashes */
|
||||
|
||||
switch (origin) {
|
||||
case SEEK_END:
|
||||
if (unlikely(offset > 0))
|
||||
goto out_err; /* not supported for directories */
|
||||
|
||||
/* so only negative offsets are left, does that have a
|
||||
* meaning for directories at all? */
|
||||
if (dx_dir)
|
||||
offset += ext4_get_htree_eof(file);
|
||||
else
|
||||
offset += inode->i_size;
|
||||
break;
|
||||
case SEEK_CUR:
|
||||
/*
|
||||
* Here we special-case the lseek(fd, 0, SEEK_CUR)
|
||||
* position-querying operation. Avoid rewriting the "same"
|
||||
* f_pos value back to the file because a concurrent read(),
|
||||
* write() or lseek() might have altered it
|
||||
*/
|
||||
if (offset == 0) {
|
||||
offset = file->f_pos;
|
||||
goto out_ok;
|
||||
}
|
||||
|
||||
offset += file->f_pos;
|
||||
break;
|
||||
}
|
||||
|
||||
if (unlikely(offset < 0))
|
||||
goto out_err;
|
||||
|
||||
if (!dx_dir) {
|
||||
if (offset > inode->i_sb->s_maxbytes)
|
||||
goto out_err;
|
||||
} else if (offset > ext4_get_htree_eof(file))
|
||||
goto out_err;
|
||||
|
||||
/* Special lock needed here? */
|
||||
if (offset != file->f_pos) {
|
||||
file->f_pos = offset;
|
||||
file->f_version = 0;
|
||||
}
|
||||
|
||||
out_ok:
|
||||
ret = offset;
|
||||
out_err:
|
||||
mutex_unlock(&inode->i_mutex);
|
||||
|
||||
return ret;
|
||||
if (likely(dx_dir))
|
||||
return generic_file_llseek_size(file, offset, origin,
|
||||
htree_max, htree_max);
|
||||
else
|
||||
return ext4_llseek(file, offset, origin);
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -211,9 +211,9 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
|
|||
}
|
||||
|
||||
/*
|
||||
* ext4_llseek() copied from generic_file_llseek() to handle both
|
||||
* block-mapped and extent-mapped maxbytes values. This should
|
||||
* otherwise be identical with generic_file_llseek().
|
||||
* ext4_llseek() handles both block-mapped and extent-mapped maxbytes values
|
||||
* by calling generic_file_llseek_size() with the appropriate maxbytes
|
||||
* value for each.
|
||||
*/
|
||||
loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
|
||||
{
|
||||
|
@ -225,7 +225,8 @@ loff_t ext4_llseek(struct file *file, loff_t offset, int origin)
|
|||
else
|
||||
maxbytes = inode->i_sb->s_maxbytes;
|
||||
|
||||
return generic_file_llseek_size(file, offset, origin, maxbytes);
|
||||
return generic_file_llseek_size(file, offset, origin,
|
||||
maxbytes, i_size_read(inode));
|
||||
}
|
||||
|
||||
const struct file_operations ext4_file_operations = {
|
||||
|
|
|
@ -135,14 +135,7 @@ static int ext4_sync_parent(struct inode *inode)
|
|||
inode = igrab(inode);
|
||||
while (ext4_test_inode_state(inode, EXT4_STATE_NEWENTRY)) {
|
||||
ext4_clear_inode_state(inode, EXT4_STATE_NEWENTRY);
|
||||
dentry = NULL;
|
||||
spin_lock(&inode->i_lock);
|
||||
if (!list_empty(&inode->i_dentry)) {
|
||||
dentry = list_first_entry(&inode->i_dentry,
|
||||
struct dentry, d_alias);
|
||||
dget(dentry);
|
||||
}
|
||||
spin_unlock(&inode->i_lock);
|
||||
dentry = d_find_any_alias(inode);
|
||||
if (!dentry)
|
||||
break;
|
||||
next = igrab(dentry->d_parent->d_inode);
|
||||
|
@ -232,7 +225,7 @@ int ext4_sync_file(struct file *file, loff_t start, loff_t end, int datasync)
|
|||
|
||||
if (!journal) {
|
||||
ret = __sync_inode(inode, datasync);
|
||||
if (!ret && !list_empty(&inode->i_dentry))
|
||||
if (!ret && !hlist_empty(&inode->i_dentry))
|
||||
ret = ext4_sync_parent(inode);
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -389,7 +389,7 @@ group_add_out:
|
|||
if (err)
|
||||
return err;
|
||||
|
||||
err = mnt_want_write(filp->f_path.mnt);
|
||||
err = mnt_want_write_file(filp);
|
||||
if (err)
|
||||
goto resizefs_out;
|
||||
|
||||
|
@ -401,7 +401,7 @@ group_add_out:
|
|||
}
|
||||
if (err == 0)
|
||||
err = err2;
|
||||
mnt_drop_write(filp->f_path.mnt);
|
||||
mnt_drop_write_file(filp);
|
||||
resizefs_out:
|
||||
ext4_resize_end(sb);
|
||||
return err;
|
||||
|
|
|
@ -1312,7 +1312,7 @@ errout:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
static struct dentry *ext4_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
struct ext4_dir_entry_2 *de;
|
||||
|
@ -2072,8 +2072,8 @@ static int ext4_add_nondir(handle_t *handle,
|
|||
int err = ext4_add_entry(handle, dentry, inode);
|
||||
if (!err) {
|
||||
ext4_mark_inode_dirty(handle, inode);
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
return 0;
|
||||
}
|
||||
drop_nlink(inode);
|
||||
|
@ -2091,7 +2091,7 @@ static int ext4_add_nondir(handle_t *handle,
|
|||
* with d_instantiate().
|
||||
*/
|
||||
static int ext4_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
handle_t *handle;
|
||||
struct inode *inode;
|
||||
|
@ -2249,8 +2249,8 @@ out_clear_inode:
|
|||
err = ext4_mark_inode_dirty(handle, dir);
|
||||
if (err)
|
||||
goto out_clear_inode;
|
||||
d_instantiate(dentry, inode);
|
||||
unlock_new_inode(inode);
|
||||
d_instantiate(dentry, inode);
|
||||
out_stop:
|
||||
brelse(dir_block);
|
||||
ext4_journal_stop(handle);
|
||||
|
|
|
@ -4325,6 +4325,11 @@ static int ext4_sync_fs(struct super_block *sb, int wait)
|
|||
|
||||
trace_ext4_sync_fs(sb, wait);
|
||||
flush_workqueue(sbi->dio_unwritten_wq);
|
||||
/*
|
||||
* Writeback quota in non-journalled quota case - journalled quota has
|
||||
* no dirty dquots
|
||||
*/
|
||||
dquot_writeback_dquots(sb, -1);
|
||||
if (jbd2_journal_start_commit(sbi->s_journal, &target)) {
|
||||
if (wait)
|
||||
jbd2_log_wait_commit(sbi->s_journal, target);
|
||||
|
|
|
@ -201,7 +201,7 @@ static const struct dentry_operations msdos_dentry_operations = {
|
|||
|
||||
/***** Get inode using directory and name */
|
||||
static struct dentry *msdos_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct fat_slot_info sinfo;
|
||||
|
@ -265,7 +265,7 @@ static int msdos_add_entry(struct inode *dir, const unsigned char *name,
|
|||
|
||||
/***** Create a file */
|
||||
static int msdos_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode = NULL;
|
||||
|
|
|
@ -41,9 +41,9 @@ static int vfat_revalidate_shortname(struct dentry *dentry)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
static int vfat_revalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
if (nd && nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
/* This is not negative dentry. Always valid. */
|
||||
|
@ -52,9 +52,9 @@ static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
return vfat_revalidate_shortname(dentry);
|
||||
}
|
||||
|
||||
static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
|
||||
static int vfat_revalidate_ci(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
if (nd && nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
/*
|
||||
|
@ -74,7 +74,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
|
|||
* This may be nfsd (or something), anyway, we can't see the
|
||||
* intent of this. So, since this can be for creation, drop it.
|
||||
*/
|
||||
if (!nd)
|
||||
if (!flags)
|
||||
return 0;
|
||||
|
||||
/*
|
||||
|
@ -82,7 +82,7 @@ static int vfat_revalidate_ci(struct dentry *dentry, struct nameidata *nd)
|
|||
* case sensitive name which is specified by user if this is
|
||||
* for creation.
|
||||
*/
|
||||
if (nd->flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
|
||||
if (flags & (LOOKUP_CREATE | LOOKUP_RENAME_TARGET))
|
||||
return 0;
|
||||
|
||||
return vfat_revalidate_shortname(dentry);
|
||||
|
@ -714,7 +714,7 @@ static int vfat_d_anon_disconn(struct dentry *dentry)
|
|||
}
|
||||
|
||||
static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct fat_slot_info sinfo;
|
||||
|
@ -772,7 +772,7 @@ error:
|
|||
}
|
||||
|
||||
static int vfat_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
struct super_block *sb = dir->i_sb;
|
||||
struct inode *inode;
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <linux/lglock.h>
|
||||
#include <linux/percpu_counter.h>
|
||||
#include <linux/percpu.h>
|
||||
#include <linux/hardirq.h>
|
||||
#include <linux/task_work.h>
|
||||
#include <linux/ima.h>
|
||||
|
||||
#include <linux/atomic.h>
|
||||
|
@ -251,7 +253,6 @@ static void __fput(struct file *file)
|
|||
}
|
||||
fops_put(file->f_op);
|
||||
put_pid(file->f_owner.pid);
|
||||
file_sb_list_del(file);
|
||||
if ((file->f_mode & (FMODE_READ | FMODE_WRITE)) == FMODE_READ)
|
||||
i_readcount_dec(inode);
|
||||
if (file->f_mode & FMODE_WRITE)
|
||||
|
@ -263,10 +264,77 @@ static void __fput(struct file *file)
|
|||
mntput(mnt);
|
||||
}
|
||||
|
||||
static DEFINE_SPINLOCK(delayed_fput_lock);
|
||||
static LIST_HEAD(delayed_fput_list);
|
||||
static void delayed_fput(struct work_struct *unused)
|
||||
{
|
||||
LIST_HEAD(head);
|
||||
spin_lock_irq(&delayed_fput_lock);
|
||||
list_splice_init(&delayed_fput_list, &head);
|
||||
spin_unlock_irq(&delayed_fput_lock);
|
||||
while (!list_empty(&head)) {
|
||||
struct file *f = list_first_entry(&head, struct file, f_u.fu_list);
|
||||
list_del_init(&f->f_u.fu_list);
|
||||
__fput(f);
|
||||
}
|
||||
}
|
||||
|
||||
static void ____fput(struct callback_head *work)
|
||||
{
|
||||
__fput(container_of(work, struct file, f_u.fu_rcuhead));
|
||||
}
|
||||
|
||||
/*
|
||||
* If kernel thread really needs to have the final fput() it has done
|
||||
* to complete, call this. The only user right now is the boot - we
|
||||
* *do* need to make sure our writes to binaries on initramfs has
|
||||
* not left us with opened struct file waiting for __fput() - execve()
|
||||
* won't work without that. Please, don't add more callers without
|
||||
* very good reasons; in particular, never call that with locks
|
||||
* held and never call that from a thread that might need to do
|
||||
* some work on any kind of umount.
|
||||
*/
|
||||
void flush_delayed_fput(void)
|
||||
{
|
||||
delayed_fput(NULL);
|
||||
}
|
||||
|
||||
static DECLARE_WORK(delayed_fput_work, delayed_fput);
|
||||
|
||||
void fput(struct file *file)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count))
|
||||
if (atomic_long_dec_and_test(&file->f_count)) {
|
||||
struct task_struct *task = current;
|
||||
file_sb_list_del(file);
|
||||
if (unlikely(in_interrupt() || task->flags & PF_KTHREAD)) {
|
||||
unsigned long flags;
|
||||
spin_lock_irqsave(&delayed_fput_lock, flags);
|
||||
list_add(&file->f_u.fu_list, &delayed_fput_list);
|
||||
schedule_work(&delayed_fput_work);
|
||||
spin_unlock_irqrestore(&delayed_fput_lock, flags);
|
||||
return;
|
||||
}
|
||||
init_task_work(&file->f_u.fu_rcuhead, ____fput);
|
||||
task_work_add(task, &file->f_u.fu_rcuhead, true);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* synchronous analog of fput(); for kernel threads that might be needed
|
||||
* in some umount() (and thus can't use flush_delayed_fput() without
|
||||
* risking deadlocks), need to wait for completion of __fput() and know
|
||||
* for this specific struct file it won't involve anything that would
|
||||
* need them. Use only if you really need it - at the very least,
|
||||
* don't blindly convert fput() by kernel thread to that.
|
||||
*/
|
||||
void __fput_sync(struct file *file)
|
||||
{
|
||||
if (atomic_long_dec_and_test(&file->f_count)) {
|
||||
struct task_struct *task = current;
|
||||
file_sb_list_del(file);
|
||||
BUG_ON(!(task->flags & PF_KTHREAD));
|
||||
__fput(file);
|
||||
}
|
||||
}
|
||||
|
||||
EXPORT_SYMBOL(fput);
|
||||
|
@ -483,10 +551,8 @@ void mark_files_ro(struct super_block *sb)
|
|||
{
|
||||
struct file *f;
|
||||
|
||||
retry:
|
||||
lg_global_lock(&files_lglock);
|
||||
do_file_list_for_each_entry(sb, f) {
|
||||
struct vfsmount *mnt;
|
||||
if (!S_ISREG(f->f_path.dentry->d_inode->i_mode))
|
||||
continue;
|
||||
if (!file_count(f))
|
||||
|
@ -499,12 +565,7 @@ retry:
|
|||
if (file_check_writeable(f) != 0)
|
||||
continue;
|
||||
file_release_write(f);
|
||||
mnt = mntget(f->f_path.mnt);
|
||||
/* This can sleep, so we can't hold the spinlock. */
|
||||
lg_global_unlock(&files_lglock);
|
||||
mnt_drop_write(mnt);
|
||||
mntput(mnt);
|
||||
goto retry;
|
||||
mnt_drop_write_file(f);
|
||||
} while_file_list_for_each_entry;
|
||||
lg_global_unlock(&files_lglock);
|
||||
}
|
||||
|
|
|
@ -48,7 +48,7 @@
|
|||
#define VXFS_BLOCK_PER_PAGE(sbp) ((PAGE_CACHE_SIZE / (sbp)->s_blocksize))
|
||||
|
||||
|
||||
static struct dentry * vxfs_lookup(struct inode *, struct dentry *, struct nameidata *);
|
||||
static struct dentry * vxfs_lookup(struct inode *, struct dentry *, unsigned int);
|
||||
static int vxfs_readdir(struct file *, void *, filldir_t);
|
||||
|
||||
const struct inode_operations vxfs_dir_inode_ops = {
|
||||
|
@ -203,7 +203,7 @@ vxfs_inode_by_name(struct inode *dip, struct dentry *dp)
|
|||
* in the return pointer.
|
||||
*/
|
||||
static struct dentry *
|
||||
vxfs_lookup(struct inode *dip, struct dentry *dp, struct nameidata *nd)
|
||||
vxfs_lookup(struct inode *dip, struct dentry *dp, unsigned int flags)
|
||||
{
|
||||
struct inode *ip = NULL;
|
||||
ino_t ino;
|
||||
|
|
|
@ -1315,6 +1315,8 @@ void writeback_inodes_sb_nr(struct super_block *sb,
|
|||
.reason = reason,
|
||||
};
|
||||
|
||||
if (sb->s_bdi == &noop_backing_dev_info)
|
||||
return;
|
||||
WARN_ON(!rwsem_is_locked(&sb->s_umount));
|
||||
bdi_queue_work(sb->s_bdi, &work);
|
||||
wait_for_completion(&done);
|
||||
|
@ -1398,6 +1400,9 @@ void sync_inodes_sb(struct super_block *sb)
|
|||
.reason = WB_REASON_SYNC,
|
||||
};
|
||||
|
||||
/* Nothing to do? */
|
||||
if (sb->s_bdi == &noop_backing_dev_info)
|
||||
return;
|
||||
WARN_ON(!rwsem_is_locked(&sb->s_umount));
|
||||
|
||||
bdi_queue_work(sb->s_bdi, &work);
|
||||
|
|
|
@ -6,18 +6,6 @@
|
|||
#include <linux/fs_struct.h>
|
||||
#include "internal.h"
|
||||
|
||||
static inline void path_get_longterm(struct path *path)
|
||||
{
|
||||
path_get(path);
|
||||
mnt_make_longterm(path->mnt);
|
||||
}
|
||||
|
||||
static inline void path_put_longterm(struct path *path)
|
||||
{
|
||||
mnt_make_shortterm(path->mnt);
|
||||
path_put(path);
|
||||
}
|
||||
|
||||
/*
|
||||
* Replace the fs->{rootmnt,root} with {mnt,dentry}. Put the old values.
|
||||
* It can block.
|
||||
|
@ -26,7 +14,7 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
|
|||
{
|
||||
struct path old_root;
|
||||
|
||||
path_get_longterm(path);
|
||||
path_get(path);
|
||||
spin_lock(&fs->lock);
|
||||
write_seqcount_begin(&fs->seq);
|
||||
old_root = fs->root;
|
||||
|
@ -34,7 +22,7 @@ void set_fs_root(struct fs_struct *fs, struct path *path)
|
|||
write_seqcount_end(&fs->seq);
|
||||
spin_unlock(&fs->lock);
|
||||
if (old_root.dentry)
|
||||
path_put_longterm(&old_root);
|
||||
path_put(&old_root);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -45,7 +33,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
|
|||
{
|
||||
struct path old_pwd;
|
||||
|
||||
path_get_longterm(path);
|
||||
path_get(path);
|
||||
spin_lock(&fs->lock);
|
||||
write_seqcount_begin(&fs->seq);
|
||||
old_pwd = fs->pwd;
|
||||
|
@ -54,7 +42,7 @@ void set_fs_pwd(struct fs_struct *fs, struct path *path)
|
|||
spin_unlock(&fs->lock);
|
||||
|
||||
if (old_pwd.dentry)
|
||||
path_put_longterm(&old_pwd);
|
||||
path_put(&old_pwd);
|
||||
}
|
||||
|
||||
static inline int replace_path(struct path *p, const struct path *old, const struct path *new)
|
||||
|
@ -84,7 +72,7 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
|
|||
write_seqcount_end(&fs->seq);
|
||||
while (hits--) {
|
||||
count++;
|
||||
path_get_longterm(new_root);
|
||||
path_get(new_root);
|
||||
}
|
||||
spin_unlock(&fs->lock);
|
||||
}
|
||||
|
@ -92,13 +80,13 @@ void chroot_fs_refs(struct path *old_root, struct path *new_root)
|
|||
} while_each_thread(g, p);
|
||||
read_unlock(&tasklist_lock);
|
||||
while (count--)
|
||||
path_put_longterm(old_root);
|
||||
path_put(old_root);
|
||||
}
|
||||
|
||||
void free_fs_struct(struct fs_struct *fs)
|
||||
{
|
||||
path_put_longterm(&fs->root);
|
||||
path_put_longterm(&fs->pwd);
|
||||
path_put(&fs->root);
|
||||
path_put(&fs->pwd);
|
||||
kmem_cache_free(fs_cachep, fs);
|
||||
}
|
||||
|
||||
|
@ -132,9 +120,9 @@ struct fs_struct *copy_fs_struct(struct fs_struct *old)
|
|||
|
||||
spin_lock(&old->lock);
|
||||
fs->root = old->root;
|
||||
path_get_longterm(&fs->root);
|
||||
path_get(&fs->root);
|
||||
fs->pwd = old->pwd;
|
||||
path_get_longterm(&fs->pwd);
|
||||
path_get(&fs->pwd);
|
||||
spin_unlock(&old->lock);
|
||||
}
|
||||
return fs;
|
||||
|
|
107
fs/fuse/dir.c
107
fs/fuse/dir.c
|
@ -154,7 +154,7 @@ u64 fuse_get_attr_version(struct fuse_conn *fc)
|
|||
* the lookup once more. If the lookup results in the same inode,
|
||||
* then refresh the attributes, timeouts and mark the dentry valid.
|
||||
*/
|
||||
static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
|
||||
static int fuse_dentry_revalidate(struct dentry *entry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
|
||||
|
@ -174,7 +174,7 @@ static int fuse_dentry_revalidate(struct dentry *entry, struct nameidata *nd)
|
|||
if (!inode)
|
||||
return 0;
|
||||
|
||||
if (nd && (nd->flags & LOOKUP_RCU))
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
fc = get_fuse_conn(inode);
|
||||
|
@ -249,7 +249,7 @@ static struct dentry *fuse_d_add_directory(struct dentry *entry,
|
|||
/* This tries to shrink the subtree below alias */
|
||||
fuse_invalidate_entry(alias);
|
||||
dput(alias);
|
||||
if (!list_empty(&inode->i_dentry))
|
||||
if (!hlist_empty(&inode->i_dentry))
|
||||
return ERR_PTR(-EBUSY);
|
||||
} else {
|
||||
dput(alias);
|
||||
|
@ -316,7 +316,7 @@ int fuse_lookup_name(struct super_block *sb, u64 nodeid, struct qstr *name,
|
|||
}
|
||||
|
||||
static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
int err;
|
||||
struct fuse_entry_out outarg;
|
||||
|
@ -370,7 +370,8 @@ static struct dentry *fuse_lookup(struct inode *dir, struct dentry *entry,
|
|||
* 'mknod' + 'open' requests.
|
||||
*/
|
||||
static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
||||
umode_t mode, struct nameidata *nd)
|
||||
struct file *file, unsigned flags,
|
||||
umode_t mode, int *opened)
|
||||
{
|
||||
int err;
|
||||
struct inode *inode;
|
||||
|
@ -381,15 +382,11 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
|||
struct fuse_open_out outopen;
|
||||
struct fuse_entry_out outentry;
|
||||
struct fuse_file *ff;
|
||||
struct file *file;
|
||||
int flags = nd->intent.open.flags;
|
||||
|
||||
if (fc->no_create)
|
||||
return -ENOSYS;
|
||||
|
||||
forget = fuse_alloc_forget();
|
||||
err = -ENOMEM;
|
||||
if (!forget)
|
||||
return -ENOMEM;
|
||||
goto out_err;
|
||||
|
||||
req = fuse_get_req(fc);
|
||||
err = PTR_ERR(req);
|
||||
|
@ -428,11 +425,8 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
|||
req->out.args[1].value = &outopen;
|
||||
fuse_request_send(fc, req);
|
||||
err = req->out.h.error;
|
||||
if (err) {
|
||||
if (err == -ENOSYS)
|
||||
fc->no_create = 1;
|
||||
if (err)
|
||||
goto out_free_ff;
|
||||
}
|
||||
|
||||
err = -EIO;
|
||||
if (!S_ISREG(outentry.attr.mode) || invalid_nodeid(outentry.nodeid))
|
||||
|
@ -448,28 +442,74 @@ static int fuse_create_open(struct inode *dir, struct dentry *entry,
|
|||
flags &= ~(O_CREAT | O_EXCL | O_TRUNC);
|
||||
fuse_sync_release(ff, flags);
|
||||
fuse_queue_forget(fc, forget, outentry.nodeid, 1);
|
||||
return -ENOMEM;
|
||||
err = -ENOMEM;
|
||||
goto out_err;
|
||||
}
|
||||
kfree(forget);
|
||||
d_instantiate(entry, inode);
|
||||
fuse_change_entry_timeout(entry, &outentry);
|
||||
fuse_invalidate_attr(dir);
|
||||
file = lookup_instantiate_filp(nd, entry, generic_file_open);
|
||||
if (IS_ERR(file)) {
|
||||
err = finish_open(file, entry, generic_file_open, opened);
|
||||
if (err) {
|
||||
fuse_sync_release(ff, flags);
|
||||
return PTR_ERR(file);
|
||||
} else {
|
||||
file->private_data = fuse_file_get(ff);
|
||||
fuse_finish_open(inode, file);
|
||||
}
|
||||
file->private_data = fuse_file_get(ff);
|
||||
fuse_finish_open(inode, file);
|
||||
return 0;
|
||||
|
||||
out_free_ff:
|
||||
fuse_file_free(ff);
|
||||
out_put_request:
|
||||
fuse_put_request(fc, req);
|
||||
out_put_forget_req:
|
||||
kfree(forget);
|
||||
return err;
|
||||
|
||||
out_free_ff:
|
||||
fuse_file_free(ff);
|
||||
out_put_request:
|
||||
fuse_put_request(fc, req);
|
||||
out_put_forget_req:
|
||||
kfree(forget);
|
||||
out_err:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int fuse_mknod(struct inode *, struct dentry *, umode_t, dev_t);
|
||||
static int fuse_atomic_open(struct inode *dir, struct dentry *entry,
|
||||
struct file *file, unsigned flags,
|
||||
umode_t mode, int *opened)
|
||||
{
|
||||
int err;
|
||||
struct fuse_conn *fc = get_fuse_conn(dir);
|
||||
struct dentry *res = NULL;
|
||||
|
||||
if (d_unhashed(entry)) {
|
||||
res = fuse_lookup(dir, entry, 0);
|
||||
if (IS_ERR(res))
|
||||
return PTR_ERR(res);
|
||||
|
||||
if (res)
|
||||
entry = res;
|
||||
}
|
||||
|
||||
if (!(flags & O_CREAT) || entry->d_inode)
|
||||
goto no_open;
|
||||
|
||||
/* Only creates */
|
||||
*opened |= FILE_CREATED;
|
||||
|
||||
if (fc->no_create)
|
||||
goto mknod;
|
||||
|
||||
err = fuse_create_open(dir, entry, file, flags, mode, opened);
|
||||
if (err == -ENOSYS) {
|
||||
fc->no_create = 1;
|
||||
goto mknod;
|
||||
}
|
||||
out_dput:
|
||||
dput(res);
|
||||
return err;
|
||||
|
||||
mknod:
|
||||
err = fuse_mknod(dir, entry, mode, 0);
|
||||
if (err)
|
||||
goto out_dput;
|
||||
no_open:
|
||||
return finish_no_open(file, res);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -571,14 +611,8 @@ static int fuse_mknod(struct inode *dir, struct dentry *entry, umode_t mode,
|
|||
}
|
||||
|
||||
static int fuse_create(struct inode *dir, struct dentry *entry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
if (nd) {
|
||||
int err = fuse_create_open(dir, entry, mode, nd);
|
||||
if (err != -ENOSYS)
|
||||
return err;
|
||||
/* Fall back on mknod */
|
||||
}
|
||||
return fuse_mknod(dir, entry, mode, 0);
|
||||
}
|
||||
|
||||
|
@ -1646,6 +1680,7 @@ static const struct inode_operations fuse_dir_inode_operations = {
|
|||
.link = fuse_link,
|
||||
.setattr = fuse_setattr,
|
||||
.create = fuse_create,
|
||||
.atomic_open = fuse_atomic_open,
|
||||
.mknod = fuse_mknod,
|
||||
.permission = fuse_permission,
|
||||
.getattr = fuse_getattr,
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
/**
|
||||
* gfs2_drevalidate - Check directory lookup consistency
|
||||
* @dentry: the mapping to check
|
||||
* @nd:
|
||||
* @flags: lookup flags
|
||||
*
|
||||
* Check to make sure the lookup necessary to arrive at this inode from its
|
||||
* parent is still good.
|
||||
|
@ -33,7 +33,7 @@
|
|||
* Returns: 1 if the dentry is ok, 0 if it isn't
|
||||
*/
|
||||
|
||||
static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
|
||||
static int gfs2_drevalidate(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct dentry *parent;
|
||||
struct gfs2_sbd *sdp;
|
||||
|
@ -44,7 +44,7 @@ static int gfs2_drevalidate(struct dentry *dentry, struct nameidata *nd)
|
|||
int error;
|
||||
int had_lock = 0;
|
||||
|
||||
if (nd && nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
parent = dget_parent(dentry);
|
||||
|
|
|
@ -755,11 +755,8 @@ fail:
|
|||
*/
|
||||
|
||||
static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
||||
umode_t mode, struct nameidata *nd)
|
||||
umode_t mode, bool excl)
|
||||
{
|
||||
int excl = 0;
|
||||
if (nd && (nd->flags & LOOKUP_EXCL))
|
||||
excl = 1;
|
||||
return gfs2_create_inode(dir, dentry, S_IFREG | mode, 0, NULL, 0, excl);
|
||||
}
|
||||
|
||||
|
@ -775,7 +772,7 @@ static int gfs2_create(struct inode *dir, struct dentry *dentry,
|
|||
*/
|
||||
|
||||
static struct dentry *gfs2_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode = gfs2_lookupi(dir, &dentry->d_name, 0);
|
||||
if (inode && !IS_ERR(inode)) {
|
||||
|
|
|
@ -1286,7 +1286,7 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
|
|||
error = -EBUSY;
|
||||
goto error_bdev;
|
||||
}
|
||||
s = sget(fs_type, test_gfs2_super, set_gfs2_super, bdev);
|
||||
s = sget(fs_type, test_gfs2_super, set_gfs2_super, flags, bdev);
|
||||
mutex_unlock(&bdev->bd_fsfreeze_mutex);
|
||||
error = PTR_ERR(s);
|
||||
if (IS_ERR(s))
|
||||
|
@ -1316,7 +1316,6 @@ static struct dentry *gfs2_mount(struct file_system_type *fs_type, int flags,
|
|||
} else {
|
||||
char b[BDEVNAME_SIZE];
|
||||
|
||||
s->s_flags = flags;
|
||||
s->s_mode = mode;
|
||||
strlcpy(s->s_id, bdevname(bdev, b), sizeof(s->s_id));
|
||||
sb_set_blocksize(s, block_size(bdev));
|
||||
|
@ -1360,7 +1359,7 @@ static struct dentry *gfs2_mount_meta(struct file_system_type *fs_type,
|
|||
dev_name, error);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super,
|
||||
s = sget(&gfs2_fs_type, test_gfs2_super, set_meta_super, flags,
|
||||
path.dentry->d_inode->i_sb->s_bdev);
|
||||
path_put(&path);
|
||||
if (IS_ERR(s)) {
|
||||
|
|
|
@ -1108,7 +1108,7 @@ void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
|
|||
}
|
||||
}
|
||||
|
||||
int gfs2_quota_sync(struct super_block *sb, int type, int wait)
|
||||
int gfs2_quota_sync(struct super_block *sb, int type)
|
||||
{
|
||||
struct gfs2_sbd *sdp = sb->s_fs_info;
|
||||
struct gfs2_quota_data **qda;
|
||||
|
@ -1154,7 +1154,7 @@ int gfs2_quota_sync(struct super_block *sb, int type, int wait)
|
|||
|
||||
static int gfs2_quota_sync_timeo(struct super_block *sb, int type)
|
||||
{
|
||||
return gfs2_quota_sync(sb, type, 0);
|
||||
return gfs2_quota_sync(sb, type);
|
||||
}
|
||||
|
||||
int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id)
|
||||
|
|
|
@ -26,7 +26,7 @@ extern int gfs2_quota_check(struct gfs2_inode *ip, u32 uid, u32 gid);
|
|||
extern void gfs2_quota_change(struct gfs2_inode *ip, s64 change,
|
||||
u32 uid, u32 gid);
|
||||
|
||||
extern int gfs2_quota_sync(struct super_block *sb, int type, int wait);
|
||||
extern int gfs2_quota_sync(struct super_block *sb, int type);
|
||||
extern int gfs2_quota_refresh(struct gfs2_sbd *sdp, int user, u32 id);
|
||||
|
||||
extern int gfs2_quota_init(struct gfs2_sbd *sdp);
|
||||
|
|
|
@ -838,7 +838,7 @@ static int gfs2_make_fs_ro(struct gfs2_sbd *sdp)
|
|||
int error;
|
||||
|
||||
flush_workqueue(gfs2_delete_workqueue);
|
||||
gfs2_quota_sync(sdp->sd_vfs, 0, 1);
|
||||
gfs2_quota_sync(sdp->sd_vfs, 0);
|
||||
gfs2_statfs_sync(sdp->sd_vfs, 0);
|
||||
|
||||
error = gfs2_glock_nq_init(sdp->sd_trans_gl, LM_ST_SHARED, GL_NOCACHE,
|
||||
|
@ -952,6 +952,8 @@ restart:
|
|||
static int gfs2_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
struct gfs2_sbd *sdp = sb->s_fs_info;
|
||||
|
||||
gfs2_quota_sync(sb, -1);
|
||||
if (wait && sdp)
|
||||
gfs2_log_flush(sdp, NULL);
|
||||
return 0;
|
||||
|
|
|
@ -168,7 +168,7 @@ static ssize_t quota_sync_store(struct gfs2_sbd *sdp, const char *buf,
|
|||
if (simple_strtol(buf, NULL, 0) != 1)
|
||||
return -EINVAL;
|
||||
|
||||
gfs2_quota_sync(sdp->sd_vfs, 0, 1);
|
||||
gfs2_quota_sync(sdp->sd_vfs, 0);
|
||||
return len;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@
|
|||
* hfs_lookup()
|
||||
*/
|
||||
static struct dentry *hfs_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
hfs_cat_rec rec;
|
||||
struct hfs_find_data fd;
|
||||
|
@ -187,7 +187,7 @@ static int hfs_dir_release(struct inode *inode, struct file *file)
|
|||
* the directory and the name (and its length) of the new file.
|
||||
*/
|
||||
static int hfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
struct inode *inode;
|
||||
int res;
|
||||
|
|
|
@ -432,7 +432,7 @@ out:
|
|||
if (inode->i_ino < HFS_FIRSTUSER_CNID)
|
||||
set_bit(HFS_FLG_ALT_MDB_DIRTY, &HFS_SB(sb)->flags);
|
||||
set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
|
||||
sb->s_dirt = 1;
|
||||
hfs_mark_mdb_dirty(sb);
|
||||
}
|
||||
return res;
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
#include <linux/mutex.h>
|
||||
#include <linux/buffer_head.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/workqueue.h>
|
||||
|
||||
#include <asm/byteorder.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
@ -137,16 +138,15 @@ struct hfs_sb_info {
|
|||
gid_t s_gid; /* The gid of all files */
|
||||
|
||||
int session, part;
|
||||
|
||||
struct nls_table *nls_io, *nls_disk;
|
||||
|
||||
struct mutex bitmap_lock;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
u16 blockoffset;
|
||||
|
||||
int fs_div;
|
||||
struct super_block *sb;
|
||||
int work_queued; /* non-zero delayed work is queued */
|
||||
struct delayed_work mdb_work; /* MDB flush delayed work */
|
||||
spinlock_t work_lock; /* protects mdb_work and work_queued */
|
||||
};
|
||||
|
||||
#define HFS_FLG_BITMAP_DIRTY 0
|
||||
|
@ -226,6 +226,9 @@ extern int hfs_compare_dentry(const struct dentry *parent,
|
|||
extern void hfs_asc2mac(struct super_block *, struct hfs_name *, struct qstr *);
|
||||
extern int hfs_mac2asc(struct super_block *, char *, const struct hfs_name *);
|
||||
|
||||
/* super.c */
|
||||
extern void hfs_mark_mdb_dirty(struct super_block *sb);
|
||||
|
||||
extern struct timezone sys_tz;
|
||||
|
||||
/*
|
||||
|
@ -253,7 +256,7 @@ static inline const char *hfs_mdb_name(struct super_block *sb)
|
|||
static inline void hfs_bitmap_dirty(struct super_block *sb)
|
||||
{
|
||||
set_bit(HFS_FLG_BITMAP_DIRTY, &HFS_SB(sb)->flags);
|
||||
sb->s_dirt = 1;
|
||||
hfs_mark_mdb_dirty(sb);
|
||||
}
|
||||
|
||||
#define sb_bread512(sb, sec, data) ({ \
|
||||
|
|
|
@ -220,7 +220,7 @@ struct inode *hfs_new_inode(struct inode *dir, struct qstr *name, umode_t mode)
|
|||
insert_inode_hash(inode);
|
||||
mark_inode_dirty(inode);
|
||||
set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
|
||||
sb->s_dirt = 1;
|
||||
hfs_mark_mdb_dirty(sb);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
@ -235,7 +235,7 @@ void hfs_delete_inode(struct inode *inode)
|
|||
if (HFS_I(inode)->cat_key.ParID == cpu_to_be32(HFS_ROOT_CNID))
|
||||
HFS_SB(sb)->root_dirs--;
|
||||
set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
|
||||
sb->s_dirt = 1;
|
||||
hfs_mark_mdb_dirty(sb);
|
||||
return;
|
||||
}
|
||||
HFS_SB(sb)->file_count--;
|
||||
|
@ -248,7 +248,7 @@ void hfs_delete_inode(struct inode *inode)
|
|||
}
|
||||
}
|
||||
set_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags);
|
||||
sb->s_dirt = 1;
|
||||
hfs_mark_mdb_dirty(sb);
|
||||
}
|
||||
|
||||
void hfs_inode_read_fork(struct inode *inode, struct hfs_extent *ext,
|
||||
|
@ -489,7 +489,7 @@ out:
|
|||
}
|
||||
|
||||
static struct dentry *hfs_file_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
hfs_cat_rec rec;
|
||||
|
@ -644,13 +644,7 @@ static int hfs_file_fsync(struct file *filp, loff_t start, loff_t end,
|
|||
|
||||
/* sync the superblock to buffers */
|
||||
sb = inode->i_sb;
|
||||
if (sb->s_dirt) {
|
||||
lock_super(sb);
|
||||
sb->s_dirt = 0;
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
hfs_mdb_commit(sb);
|
||||
unlock_super(sb);
|
||||
}
|
||||
flush_delayed_work_sync(&HFS_SB(sb)->mdb_work);
|
||||
/* .. finally sync the buffers to disk */
|
||||
err = sync_blockdev(sb->s_bdev);
|
||||
if (!ret)
|
||||
|
|
13
fs/hfs/mdb.c
13
fs/hfs/mdb.c
|
@ -260,6 +260,10 @@ void hfs_mdb_commit(struct super_block *sb)
|
|||
{
|
||||
struct hfs_mdb *mdb = HFS_SB(sb)->mdb;
|
||||
|
||||
if (sb->s_flags & MS_RDONLY)
|
||||
return;
|
||||
|
||||
lock_buffer(HFS_SB(sb)->mdb_bh);
|
||||
if (test_and_clear_bit(HFS_FLG_MDB_DIRTY, &HFS_SB(sb)->flags)) {
|
||||
/* These parameters may have been modified, so write them back */
|
||||
mdb->drLsMod = hfs_mtime();
|
||||
|
@ -283,9 +287,13 @@ void hfs_mdb_commit(struct super_block *sb)
|
|||
&mdb->drXTFlSize, NULL);
|
||||
hfs_inode_write_fork(HFS_SB(sb)->cat_tree->inode, mdb->drCTExtRec,
|
||||
&mdb->drCTFlSize, NULL);
|
||||
|
||||
lock_buffer(HFS_SB(sb)->alt_mdb_bh);
|
||||
memcpy(HFS_SB(sb)->alt_mdb, HFS_SB(sb)->mdb, HFS_SECTOR_SIZE);
|
||||
HFS_SB(sb)->alt_mdb->drAtrb |= cpu_to_be16(HFS_SB_ATTRIB_UNMNT);
|
||||
HFS_SB(sb)->alt_mdb->drAtrb &= cpu_to_be16(~HFS_SB_ATTRIB_INCNSTNT);
|
||||
unlock_buffer(HFS_SB(sb)->alt_mdb_bh);
|
||||
|
||||
mark_buffer_dirty(HFS_SB(sb)->alt_mdb_bh);
|
||||
sync_dirty_buffer(HFS_SB(sb)->alt_mdb_bh);
|
||||
}
|
||||
|
@ -308,7 +316,11 @@ void hfs_mdb_commit(struct super_block *sb)
|
|||
break;
|
||||
}
|
||||
len = min((int)sb->s_blocksize - off, size);
|
||||
|
||||
lock_buffer(bh);
|
||||
memcpy(bh->b_data + off, ptr, len);
|
||||
unlock_buffer(bh);
|
||||
|
||||
mark_buffer_dirty(bh);
|
||||
brelse(bh);
|
||||
block++;
|
||||
|
@ -317,6 +329,7 @@ void hfs_mdb_commit(struct super_block *sb)
|
|||
size -= len;
|
||||
}
|
||||
}
|
||||
unlock_buffer(HFS_SB(sb)->mdb_bh);
|
||||
}
|
||||
|
||||
void hfs_mdb_close(struct super_block *sb)
|
||||
|
|
|
@ -29,43 +29,9 @@ static struct kmem_cache *hfs_inode_cachep;
|
|||
|
||||
MODULE_LICENSE("GPL");
|
||||
|
||||
/*
|
||||
* hfs_write_super()
|
||||
*
|
||||
* Description:
|
||||
* This function is called by the VFS only. When the filesystem
|
||||
* is mounted r/w it updates the MDB on disk.
|
||||
* Input Variable(s):
|
||||
* struct super_block *sb: Pointer to the hfs superblock
|
||||
* Output Variable(s):
|
||||
* NONE
|
||||
* Returns:
|
||||
* void
|
||||
* Preconditions:
|
||||
* 'sb' points to a "valid" (struct super_block).
|
||||
* Postconditions:
|
||||
* The MDB is marked 'unsuccessfully unmounted' by clearing bit 8 of drAtrb
|
||||
* (hfs_put_super() must set this flag!). Some MDB fields are updated
|
||||
* and the MDB buffer is written to disk by calling hfs_mdb_commit().
|
||||
*/
|
||||
static void hfs_write_super(struct super_block *sb)
|
||||
{
|
||||
lock_super(sb);
|
||||
sb->s_dirt = 0;
|
||||
|
||||
/* sync everything to the buffers */
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
hfs_mdb_commit(sb);
|
||||
unlock_super(sb);
|
||||
}
|
||||
|
||||
static int hfs_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
lock_super(sb);
|
||||
hfs_mdb_commit(sb);
|
||||
sb->s_dirt = 0;
|
||||
unlock_super(sb);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -78,13 +44,44 @@ static int hfs_sync_fs(struct super_block *sb, int wait)
|
|||
*/
|
||||
static void hfs_put_super(struct super_block *sb)
|
||||
{
|
||||
if (sb->s_dirt)
|
||||
hfs_write_super(sb);
|
||||
cancel_delayed_work_sync(&HFS_SB(sb)->mdb_work);
|
||||
hfs_mdb_close(sb);
|
||||
/* release the MDB's resources */
|
||||
hfs_mdb_put(sb);
|
||||
}
|
||||
|
||||
static void flush_mdb(struct work_struct *work)
|
||||
{
|
||||
struct hfs_sb_info *sbi;
|
||||
struct super_block *sb;
|
||||
|
||||
sbi = container_of(work, struct hfs_sb_info, mdb_work.work);
|
||||
sb = sbi->sb;
|
||||
|
||||
spin_lock(&sbi->work_lock);
|
||||
sbi->work_queued = 0;
|
||||
spin_unlock(&sbi->work_lock);
|
||||
|
||||
hfs_mdb_commit(sb);
|
||||
}
|
||||
|
||||
void hfs_mark_mdb_dirty(struct super_block *sb)
|
||||
{
|
||||
struct hfs_sb_info *sbi = HFS_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->mdb_work, delay);
|
||||
sbi->work_queued = 1;
|
||||
}
|
||||
spin_unlock(&sbi->work_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* hfs_statfs()
|
||||
*
|
||||
|
@ -184,7 +181,6 @@ static const struct super_operations hfs_super_operations = {
|
|||
.write_inode = hfs_write_inode,
|
||||
.evict_inode = hfs_evict_inode,
|
||||
.put_super = hfs_put_super,
|
||||
.write_super = hfs_write_super,
|
||||
.sync_fs = hfs_sync_fs,
|
||||
.statfs = hfs_statfs,
|
||||
.remount_fs = hfs_remount,
|
||||
|
@ -387,7 +383,10 @@ static int hfs_fill_super(struct super_block *sb, void *data, int silent)
|
|||
if (!sbi)
|
||||
return -ENOMEM;
|
||||
|
||||
sbi->sb = sb;
|
||||
sb->s_fs_info = sbi;
|
||||
spin_lock_init(&sbi->work_lock);
|
||||
INIT_DELAYED_WORK(&sbi->mdb_work, flush_mdb);
|
||||
|
||||
res = -EINVAL;
|
||||
if (!parse_options((char *)data, sbi)) {
|
||||
|
|
|
@ -13,12 +13,12 @@
|
|||
|
||||
/* dentry case-handling: just lowercase everything */
|
||||
|
||||
static int hfs_revalidate_dentry(struct dentry *dentry, struct nameidata *nd)
|
||||
static int hfs_revalidate_dentry(struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
int diff;
|
||||
|
||||
if (nd->flags & LOOKUP_RCU)
|
||||
if (flags & LOOKUP_RCU)
|
||||
return -ECHILD;
|
||||
|
||||
inode = dentry->d_inode;
|
||||
|
|
|
@ -153,7 +153,7 @@ done:
|
|||
kunmap(page);
|
||||
*max = offset + (curr - pptr) * 32 + i - start;
|
||||
sbi->free_blocks -= *max;
|
||||
sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
dprint(DBG_BITMAP, "-> %u,%u\n", start, *max);
|
||||
out:
|
||||
mutex_unlock(&sbi->alloc_mutex);
|
||||
|
@ -228,7 +228,7 @@ out:
|
|||
set_page_dirty(page);
|
||||
kunmap(page);
|
||||
sbi->free_blocks += len;
|
||||
sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
mutex_unlock(&sbi->alloc_mutex);
|
||||
|
||||
return 0;
|
||||
|
|
|
@ -25,7 +25,7 @@ static inline void hfsplus_instantiate(struct dentry *dentry,
|
|||
|
||||
/* Find the entry inside dir named dentry->d_name */
|
||||
static struct dentry *hfsplus_lookup(struct inode *dir, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode = NULL;
|
||||
struct hfs_find_data fd;
|
||||
|
@ -316,7 +316,7 @@ static int hfsplus_link(struct dentry *src_dentry, struct inode *dst_dir,
|
|||
inode->i_ctime = CURRENT_TIME_SEC;
|
||||
mark_inode_dirty(inode);
|
||||
sbi->file_count++;
|
||||
dst_dir->i_sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(dst_dir->i_sb);
|
||||
out:
|
||||
mutex_unlock(&sbi->vh_mutex);
|
||||
return res;
|
||||
|
@ -465,7 +465,7 @@ out:
|
|||
}
|
||||
|
||||
static int hfsplus_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
return hfsplus_mknod(dir, dentry, mode, 0);
|
||||
}
|
||||
|
|
|
@ -153,8 +153,11 @@ struct hfsplus_sb_info {
|
|||
gid_t gid;
|
||||
|
||||
int part, session;
|
||||
|
||||
unsigned long flags;
|
||||
|
||||
int work_queued; /* non-zero delayed work is queued */
|
||||
struct delayed_work sync_work; /* FS sync delayed work */
|
||||
spinlock_t work_lock; /* protects sync_work and work_queued */
|
||||
};
|
||||
|
||||
#define HFSPLUS_SB_WRITEBACKUP 0
|
||||
|
@ -428,7 +431,7 @@ int hfsplus_show_options(struct seq_file *, struct dentry *);
|
|||
|
||||
/* super.c */
|
||||
struct inode *hfsplus_iget(struct super_block *, unsigned long);
|
||||
int hfsplus_sync_fs(struct super_block *sb, int wait);
|
||||
void hfsplus_mark_mdb_dirty(struct super_block *sb);
|
||||
|
||||
/* tables.c */
|
||||
extern u16 hfsplus_case_fold_table[];
|
||||
|
|
|
@ -168,7 +168,7 @@ const struct dentry_operations hfsplus_dentry_operations = {
|
|||
};
|
||||
|
||||
static struct dentry *hfsplus_file_lookup(struct inode *dir,
|
||||
struct dentry *dentry, struct nameidata *nd)
|
||||
struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
struct hfs_find_data fd;
|
||||
struct super_block *sb = dir->i_sb;
|
||||
|
@ -431,7 +431,7 @@ struct inode *hfsplus_new_inode(struct super_block *sb, umode_t mode)
|
|||
sbi->file_count++;
|
||||
insert_inode_hash(inode);
|
||||
mark_inode_dirty(inode);
|
||||
sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
|
||||
return inode;
|
||||
}
|
||||
|
@ -442,7 +442,7 @@ void hfsplus_delete_inode(struct inode *inode)
|
|||
|
||||
if (S_ISDIR(inode->i_mode)) {
|
||||
HFSPLUS_SB(sb)->folder_count--;
|
||||
sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
return;
|
||||
}
|
||||
HFSPLUS_SB(sb)->file_count--;
|
||||
|
@ -455,7 +455,7 @@ void hfsplus_delete_inode(struct inode *inode)
|
|||
inode->i_size = 0;
|
||||
hfsplus_file_truncate(inode);
|
||||
}
|
||||
sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(sb);
|
||||
}
|
||||
|
||||
void hfsplus_inode_read_fork(struct inode *inode, struct hfsplus_fork_raw *fork)
|
||||
|
|
|
@ -124,7 +124,7 @@ static int hfsplus_system_write_inode(struct inode *inode)
|
|||
|
||||
if (fork->total_size != cpu_to_be64(inode->i_size)) {
|
||||
set_bit(HFSPLUS_SB_WRITEBACKUP, &sbi->flags);
|
||||
inode->i_sb->s_dirt = 1;
|
||||
hfsplus_mark_mdb_dirty(inode->i_sb);
|
||||
}
|
||||
hfsplus_inode_write_fork(inode, fork);
|
||||
if (tree)
|
||||
|
@ -161,7 +161,7 @@ static void hfsplus_evict_inode(struct inode *inode)
|
|||
}
|
||||
}
|
||||
|
||||
int hfsplus_sync_fs(struct super_block *sb, int wait)
|
||||
static int hfsplus_sync_fs(struct super_block *sb, int wait)
|
||||
{
|
||||
struct hfsplus_sb_info *sbi = HFSPLUS_SB(sb);
|
||||
struct hfsplus_vh *vhdr = sbi->s_vhdr;
|
||||
|
@ -171,9 +171,7 @@ int hfsplus_sync_fs(struct super_block *sb, int wait)
|
|||
if (!wait)
|
||||
return 0;
|
||||
|
||||
dprint(DBG_SUPER, "hfsplus_write_super\n");
|
||||
|
||||
sb->s_dirt = 0;
|
||||
dprint(DBG_SUPER, "hfsplus_sync_fs\n");
|
||||
|
||||
/*
|
||||
* Explicitly write out the special metadata inodes.
|
||||
|
@ -226,12 +224,34 @@ out:
|
|||
return error;
|
||||
}
|
||||
|
||||
static void hfsplus_write_super(struct super_block *sb)
|
||||
static void delayed_sync_fs(struct work_struct *work)
|
||||
{
|
||||
if (!(sb->s_flags & MS_RDONLY))
|
||||
hfsplus_sync_fs(sb, 1);
|
||||
else
|
||||
sb->s_dirt = 0;
|
||||
struct hfsplus_sb_info *sbi;
|
||||
|
||||
sbi = container_of(work, struct hfsplus_sb_info, sync_work.work);
|
||||
|
||||
spin_lock(&sbi->work_lock);
|
||||
sbi->work_queued = 0;
|
||||
spin_unlock(&sbi->work_lock);
|
||||
|
||||
hfsplus_sync_fs(sbi->alloc_file->i_sb, 1);
|
||||
}
|
||||
|
||||
void hfsplus_mark_mdb_dirty(struct super_block *sb)
|
||||
{
|
||||
struct hfsplus_sb_info *sbi = HFSPLUS_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->sync_work, delay);
|
||||
sbi->work_queued = 1;
|
||||
}
|
||||
spin_unlock(&sbi->work_lock);
|
||||
}
|
||||
|
||||
static void hfsplus_put_super(struct super_block *sb)
|
||||
|
@ -240,8 +260,7 @@ static void hfsplus_put_super(struct super_block *sb)
|
|||
|
||||
dprint(DBG_SUPER, "hfsplus_put_super\n");
|
||||
|
||||
if (!sb->s_fs_info)
|
||||
return;
|
||||
cancel_delayed_work_sync(&sbi->sync_work);
|
||||
|
||||
if (!(sb->s_flags & MS_RDONLY) && sbi->s_vhdr) {
|
||||
struct hfsplus_vh *vhdr = sbi->s_vhdr;
|
||||
|
@ -328,7 +347,6 @@ static const struct super_operations hfsplus_sops = {
|
|||
.write_inode = hfsplus_write_inode,
|
||||
.evict_inode = hfsplus_evict_inode,
|
||||
.put_super = hfsplus_put_super,
|
||||
.write_super = hfsplus_write_super,
|
||||
.sync_fs = hfsplus_sync_fs,
|
||||
.statfs = hfsplus_statfs,
|
||||
.remount_fs = hfsplus_remount,
|
||||
|
@ -355,6 +373,8 @@ static int hfsplus_fill_super(struct super_block *sb, void *data, int silent)
|
|||
sb->s_fs_info = sbi;
|
||||
mutex_init(&sbi->alloc_mutex);
|
||||
mutex_init(&sbi->vh_mutex);
|
||||
spin_lock_init(&sbi->work_lock);
|
||||
INIT_DELAYED_WORK(&sbi->sync_work, delayed_sync_fs);
|
||||
hfsplus_fill_defaults(sbi);
|
||||
|
||||
err = -EINVAL;
|
||||
|
|
|
@ -553,7 +553,7 @@ static int read_name(struct inode *ino, char *name)
|
|||
}
|
||||
|
||||
int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
||||
struct nameidata *nd)
|
||||
bool excl)
|
||||
{
|
||||
struct inode *inode;
|
||||
char *name;
|
||||
|
@ -595,7 +595,7 @@ int hostfs_create(struct inode *dir, struct dentry *dentry, umode_t mode,
|
|||
}
|
||||
|
||||
struct dentry *hostfs_lookup(struct inode *ino, struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
unsigned int flags)
|
||||
{
|
||||
struct inode *inode;
|
||||
char *name;
|
||||
|
|
|
@ -189,7 +189,7 @@ out:
|
|||
* to tell read_inode to read fnode or not.
|
||||
*/
|
||||
|
||||
struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
|
||||
struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
|
||||
{
|
||||
const unsigned char *name = dentry->d_name.name;
|
||||
unsigned len = dentry->d_name.len;
|
||||
|
|
Некоторые файлы не были показаны из-за слишком большого количества измененных файлов Показать больше
Загрузка…
Ссылка в новой задаче