mirror of
https://github.com/torvalds/linux.git
synced 2024-12-27 21:33:00 +00:00
Merge branch 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs
Pull vfs updates from Al Viro: "In this pile: pathname resolution rewrite. - recursion in link_path_walk() is gone. - nesting limits on symlinks are gone (the only limit remaining is that the total amount of symlinks is no more than 40, no matter how nested). - "fast" (inline) symlinks are handled without leaving rcuwalk mode. - stack footprint (independent of the nesting) is below kilobyte now, about on par with what it used to be with one level of nested symlinks and ~2.8 times lower than it used to be in the worst case. - struct nameidata is entirely private to fs/namei.c now (not even opaque pointers are being passed around). - ->follow_link() and ->put_link() calling conventions had been changed; all in-tree filesystems converted, out-of-tree should be able to follow reasonably easily. For out-of-tree conversions, see Documentation/filesystems/porting for details (and in-tree filesystems for examples of conversion). That has sat in -next since mid-May, seems to survive all testing without regressions and merges clean with v4.1" * 'for-linus-1' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs: (131 commits) turn user_{path_at,path,lpath,path_dir}() into static inlines namei: move saved_nd pointer into struct nameidata inline user_path_create() inline user_path_parent() namei: trim do_last() arguments namei: stash dfd and name into nameidata namei: fold path_cleanup() into terminate_walk() namei: saner calling conventions for filename_parentat() namei: saner calling conventions for filename_create() namei: shift nameidata down into filename_parentat() namei: make filename_lookup() reject ERR_PTR() passed as name namei: shift nameidata inside filename_lookup() namei: move putname() call into filename_lookup() namei: pass the struct path to store the result down into path_lookupat() namei: uninline set_root{,_rcu}() namei: be careful with mountpoint crossings in follow_dotdot_rcu() Documentation: remove outdated information from automount-support.txt get rid of assorted nameidata-related debris lustre: kill unused helper lustre: kill unused macro (LOOKUP_CONTINUE) ...
This commit is contained in:
commit
052b398a43
@ -50,8 +50,8 @@ prototypes:
|
||||
int (*rename2) (struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *, unsigned int);
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
const char *(*follow_link) (struct dentry *, void **);
|
||||
void (*put_link) (struct inode *, void *);
|
||||
void (*truncate) (struct inode *);
|
||||
int (*permission) (struct inode *, int, unsigned int);
|
||||
int (*get_acl)(struct inode *, int);
|
||||
|
@ -1,41 +1,15 @@
|
||||
Support is available for filesystems that wish to do automounting support (such
|
||||
as kAFS which can be found in fs/afs/). This facility includes allowing
|
||||
in-kernel mounts to be performed and mountpoint degradation to be
|
||||
requested. The latter can also be requested by userspace.
|
||||
Support is available for filesystems that wish to do automounting
|
||||
support (such as kAFS which can be found in fs/afs/ and NFS in
|
||||
fs/nfs/). This facility includes allowing in-kernel mounts to be
|
||||
performed and mountpoint degradation to be requested. The latter can
|
||||
also be requested by userspace.
|
||||
|
||||
|
||||
======================
|
||||
IN-KERNEL AUTOMOUNTING
|
||||
======================
|
||||
|
||||
A filesystem can now mount another filesystem on one of its directories by the
|
||||
following procedure:
|
||||
|
||||
(1) Give the directory a follow_link() operation.
|
||||
|
||||
When the directory is accessed, the follow_link op will be called, and
|
||||
it will be provided with the location of the mountpoint in the nameidata
|
||||
structure (vfsmount and dentry).
|
||||
|
||||
(2) Have the follow_link() op do the following steps:
|
||||
|
||||
(a) Call vfs_kern_mount() to call the appropriate filesystem to set up a
|
||||
superblock and gain a vfsmount structure representing it.
|
||||
|
||||
(b) Copy the nameidata provided as an argument and substitute the dentry
|
||||
argument into it the copy.
|
||||
|
||||
(c) Call do_add_mount() to install the new vfsmount into the namespace's
|
||||
mountpoint tree, thus making it accessible to userspace. Use the
|
||||
nameidata set up in (b) as the destination.
|
||||
|
||||
If the mountpoint will be automatically expired, then do_add_mount()
|
||||
should also be given the location of an expiration list (see further
|
||||
down).
|
||||
|
||||
(d) Release the path in the nameidata argument and substitute in the new
|
||||
vfsmount and its root dentry. The ref counts on these will need
|
||||
incrementing.
|
||||
See section "Mount Traps" of Documentation/filesystems/autofs4.txt
|
||||
|
||||
Then from userspace, you can just do something like:
|
||||
|
||||
@ -61,17 +35,18 @@ AUTOMATIC MOUNTPOINT EXPIRY
|
||||
===========================
|
||||
|
||||
Automatic expiration of mountpoints is easy, provided you've mounted the
|
||||
mountpoint to be expired in the automounting procedure outlined above.
|
||||
mountpoint to be expired in the automounting procedure outlined separately.
|
||||
|
||||
To do expiration, you need to follow these steps:
|
||||
|
||||
(3) Create at least one list off which the vfsmounts to be expired can be
|
||||
hung. Access to this list will be governed by the vfsmount_lock.
|
||||
(1) Create at least one list off which the vfsmounts to be expired can be
|
||||
hung.
|
||||
|
||||
(4) In step (2c) above, the call to do_add_mount() should be provided with a
|
||||
pointer to this list. It will hang the vfsmount off of it if it succeeds.
|
||||
(2) When a new mountpoint is created in the ->d_automount method, add
|
||||
the mnt to the list using mnt_set_expiry()
|
||||
mnt_set_expiry(newmnt, &afs_vfsmounts);
|
||||
|
||||
(5) When you want mountpoints to be expired, call mark_mounts_for_expiry()
|
||||
(3) When you want mountpoints to be expired, call mark_mounts_for_expiry()
|
||||
with a pointer to this list. This will process the list, marking every
|
||||
vfsmount thereon for potential expiry on the next call.
|
||||
|
||||
|
@ -483,3 +483,20 @@ in your dentry operations instead.
|
||||
--
|
||||
[mandatory]
|
||||
->aio_read/->aio_write are gone. Use ->read_iter/->write_iter.
|
||||
---
|
||||
[recommended]
|
||||
for embedded ("fast") symlinks just set inode->i_link to wherever the
|
||||
symlink body is and use simple_follow_link() as ->follow_link().
|
||||
--
|
||||
[mandatory]
|
||||
calling conventions for ->follow_link() have changed. Instead of returning
|
||||
cookie and using nd_set_link() to store the body to traverse, we return
|
||||
the body to traverse and store the cookie using explicit void ** argument.
|
||||
nameidata isn't passed at all - nd_jump_link() doesn't need it and
|
||||
nd_[gs]et_link() is gone.
|
||||
--
|
||||
[mandatory]
|
||||
calling conventions for ->put_link() have changed. It gets inode instead of
|
||||
dentry, it does not get nameidata at all and it gets called only when cookie
|
||||
is non-NULL. Note that link body isn't available anymore, so if you need it,
|
||||
store it as cookie.
|
||||
|
@ -350,8 +350,8 @@ struct inode_operations {
|
||||
int (*rename2) (struct inode *, struct dentry *,
|
||||
struct inode *, struct dentry *, unsigned int);
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
const char *(*follow_link) (struct dentry *, void **);
|
||||
void (*put_link) (struct inode *, void *);
|
||||
int (*permission) (struct inode *, int);
|
||||
int (*get_acl)(struct inode *, int);
|
||||
int (*setattr) (struct dentry *, struct iattr *);
|
||||
@ -436,16 +436,18 @@ otherwise noted.
|
||||
|
||||
follow_link: called by the VFS to follow a symbolic link to the
|
||||
inode it points to. Only required if you want to support
|
||||
symbolic links. This method returns a void pointer cookie
|
||||
that is passed to put_link().
|
||||
symbolic links. This method returns the symlink body
|
||||
to traverse (and possibly resets the current position with
|
||||
nd_jump_link()). If the body won't go away until the inode
|
||||
is gone, nothing else is needed; if it needs to be otherwise
|
||||
pinned, the data needed to release whatever we'd grabbed
|
||||
is to be stored in void * variable passed by address to
|
||||
follow_link() instance.
|
||||
|
||||
put_link: called by the VFS to release resources allocated by
|
||||
follow_link(). The cookie returned by follow_link() is passed
|
||||
to this method as the last parameter. It is used by
|
||||
filesystems such as NFS where page cache is not stable
|
||||
(i.e. page that was installed when the symbolic link walk
|
||||
started might not be in the page cache at the end of the
|
||||
walk).
|
||||
follow_link(). The cookie stored by follow_link() is passed
|
||||
to this method as the last parameter; only called when
|
||||
cookie isn't NULL.
|
||||
|
||||
permission: called by the VFS to check for access rights on a POSIX-like
|
||||
filesystem.
|
||||
|
@ -189,22 +189,7 @@ static inline int ll_quota_off(struct super_block *sb, int off, int remount)
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* After 3.1, kernel's nameidata.intent.open.flags is different
|
||||
* with lustre's lookup_intent.it_flags, as lustre's it_flags'
|
||||
* lower bits equal to FMODE_xxx while kernel doesn't transliterate
|
||||
* lower bits of nameidata.intent.open.flags to FMODE_xxx.
|
||||
* */
|
||||
#include <linux/version.h>
|
||||
static inline int ll_namei_to_lookup_intent_flag(int flag)
|
||||
{
|
||||
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 1, 0)
|
||||
flag = (flag & ~O_ACCMODE) | OPEN_FMODE(flag);
|
||||
#endif
|
||||
return flag;
|
||||
}
|
||||
|
||||
#include <linux/fs.h>
|
||||
|
||||
# define ll_umode_t umode_t
|
||||
|
@ -57,12 +57,6 @@
|
||||
#define VM_FAULT_RETRY 0
|
||||
#endif
|
||||
|
||||
/* Kernel 3.1 kills LOOKUP_CONTINUE, LOOKUP_PARENT is equivalent to it.
|
||||
* seem kernel commit 49084c3bb2055c401f3493c13edae14d49128ca0 */
|
||||
#ifndef LOOKUP_CONTINUE
|
||||
#define LOOKUP_CONTINUE LOOKUP_PARENT
|
||||
#endif
|
||||
|
||||
/** Only used on client-side for indicating the tail of dir hash/offset. */
|
||||
#define LL_DIR_END_OFF 0x7fffffffffffffffULL
|
||||
#define LL_DIR_END_OFF_32BIT 0x7fffffffUL
|
||||
|
@ -118,7 +118,7 @@ failed:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *ll_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct ptlrpc_request *request = NULL;
|
||||
@ -126,32 +126,22 @@ static void *ll_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
char *symname = NULL;
|
||||
|
||||
CDEBUG(D_VFSTRACE, "VFS Op\n");
|
||||
/* Limit the recursive symlink depth to 5 instead of default
|
||||
* 8 links when kernel has 4k stack to prevent stack overflow.
|
||||
* For 8k stacks we need to limit it to 7 for local servers. */
|
||||
if (THREAD_SIZE < 8192 && current->link_count >= 6) {
|
||||
rc = -ELOOP;
|
||||
} else if (THREAD_SIZE == 8192 && current->link_count >= 8) {
|
||||
rc = -ELOOP;
|
||||
} else {
|
||||
ll_inode_size_lock(inode);
|
||||
rc = ll_readlink_internal(inode, &request, &symname);
|
||||
ll_inode_size_unlock(inode);
|
||||
}
|
||||
ll_inode_size_lock(inode);
|
||||
rc = ll_readlink_internal(inode, &request, &symname);
|
||||
ll_inode_size_unlock(inode);
|
||||
if (rc) {
|
||||
ptlrpc_req_finished(request);
|
||||
request = NULL;
|
||||
symname = ERR_PTR(rc);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
nd_set_link(nd, symname);
|
||||
/* symname may contain a pointer to the request message buffer,
|
||||
* we delay request releasing until ll_put_link then.
|
||||
*/
|
||||
return request;
|
||||
*cookie = request;
|
||||
return symname;
|
||||
}
|
||||
|
||||
static void ll_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
|
||||
static void ll_put_link(struct inode *unused, void *cookie)
|
||||
{
|
||||
ptlrpc_req_finished(cookie);
|
||||
}
|
||||
|
@ -149,8 +149,6 @@ 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,
|
||||
struct inode *new_dir, struct dentry *new_dentry);
|
||||
extern void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *p);
|
||||
extern struct inode *v9fs_inode_from_fid(struct v9fs_session_info *v9ses,
|
||||
struct p9_fid *fid,
|
||||
struct super_block *sb, int new);
|
||||
|
@ -1223,101 +1223,44 @@ ino_t v9fs_qid2ino(struct p9_qid *qid)
|
||||
return i;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_readlink - read a symlink's location (internal version)
|
||||
* @dentry: dentry for symlink
|
||||
* @buffer: buffer to load symlink location into
|
||||
* @buflen: length of buffer
|
||||
*
|
||||
*/
|
||||
|
||||
static int v9fs_readlink(struct dentry *dentry, char *buffer, int buflen)
|
||||
{
|
||||
int retval;
|
||||
|
||||
struct v9fs_session_info *v9ses;
|
||||
struct p9_fid *fid;
|
||||
struct p9_wstat *st;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, " %pd\n", dentry);
|
||||
retval = -EPERM;
|
||||
v9ses = v9fs_dentry2v9ses(dentry);
|
||||
fid = v9fs_fid_lookup(dentry);
|
||||
if (IS_ERR(fid))
|
||||
return PTR_ERR(fid);
|
||||
|
||||
if (!v9fs_proto_dotu(v9ses))
|
||||
return -EBADF;
|
||||
|
||||
st = p9_client_stat(fid);
|
||||
if (IS_ERR(st))
|
||||
return PTR_ERR(st);
|
||||
|
||||
if (!(st->mode & P9_DMSYMLINK)) {
|
||||
retval = -EINVAL;
|
||||
goto done;
|
||||
}
|
||||
|
||||
/* copy extension buffer into buffer */
|
||||
retval = min(strlen(st->extension)+1, (size_t)buflen);
|
||||
memcpy(buffer, st->extension, retval);
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "%pd -> %s (%.*s)\n",
|
||||
dentry, st->extension, buflen, buffer);
|
||||
|
||||
done:
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
return retval;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_vfs_follow_link - follow a symlink path
|
||||
* @dentry: dentry for symlink
|
||||
* @nd: nameidata
|
||||
*
|
||||
* @cookie: place to pass the data to put_link()
|
||||
*/
|
||||
|
||||
static void *v9fs_vfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *v9fs_vfs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
int len = 0;
|
||||
char *link = __getname();
|
||||
struct v9fs_session_info *v9ses = v9fs_dentry2v9ses(dentry);
|
||||
struct p9_fid *fid = v9fs_fid_lookup(dentry);
|
||||
struct p9_wstat *st;
|
||||
char *res;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
|
||||
|
||||
if (!link)
|
||||
link = ERR_PTR(-ENOMEM);
|
||||
else {
|
||||
len = v9fs_readlink(dentry, link, PATH_MAX);
|
||||
if (IS_ERR(fid))
|
||||
return ERR_CAST(fid);
|
||||
|
||||
if (len < 0) {
|
||||
__putname(link);
|
||||
link = ERR_PTR(len);
|
||||
} else
|
||||
link[min(len, PATH_MAX-1)] = 0;
|
||||
if (!v9fs_proto_dotu(v9ses))
|
||||
return ERR_PTR(-EBADF);
|
||||
|
||||
st = p9_client_stat(fid);
|
||||
if (IS_ERR(st))
|
||||
return ERR_CAST(st);
|
||||
|
||||
if (!(st->mode & P9_DMSYMLINK)) {
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
return ERR_PTR(-EINVAL);
|
||||
}
|
||||
nd_set_link(nd, link);
|
||||
res = st->extension;
|
||||
st->extension = NULL;
|
||||
if (strlen(res) >= PATH_MAX)
|
||||
res[PATH_MAX - 1] = '\0';
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* v9fs_vfs_put_link - release a symlink path
|
||||
* @dentry: dentry for symlink
|
||||
* @nd: nameidata
|
||||
* @p: unused
|
||||
*
|
||||
*/
|
||||
|
||||
void
|
||||
v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
|
||||
{
|
||||
char *s = nd_get_link(nd);
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, " %pd %s\n",
|
||||
dentry, IS_ERR(s) ? "<error>" : s);
|
||||
if (!IS_ERR(s))
|
||||
__putname(s);
|
||||
p9stat_free(st);
|
||||
kfree(st);
|
||||
return *cookie = res;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1370,6 +1313,8 @@ v9fs_vfs_symlink(struct inode *dir, struct dentry *dentry, const char *symname)
|
||||
return v9fs_vfs_mkspecial(dir, dentry, P9_DMSYMLINK, symname);
|
||||
}
|
||||
|
||||
#define U32_MAX_DIGITS 10
|
||||
|
||||
/**
|
||||
* v9fs_vfs_link - create a hardlink
|
||||
* @old_dentry: dentry for file to link to
|
||||
@ -1383,7 +1328,7 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
struct dentry *dentry)
|
||||
{
|
||||
int retval;
|
||||
char *name;
|
||||
char name[1 + U32_MAX_DIGITS + 2]; /* sign + number + \n + \0 */
|
||||
struct p9_fid *oldfid;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, " %lu,%pd,%pd\n",
|
||||
@ -1393,20 +1338,12 @@ v9fs_vfs_link(struct dentry *old_dentry, struct inode *dir,
|
||||
if (IS_ERR(oldfid))
|
||||
return PTR_ERR(oldfid);
|
||||
|
||||
name = __getname();
|
||||
if (unlikely(!name)) {
|
||||
retval = -ENOMEM;
|
||||
goto clunk_fid;
|
||||
}
|
||||
|
||||
sprintf(name, "%d\n", oldfid->fid);
|
||||
retval = v9fs_vfs_mkspecial(dir, dentry, P9_DMLINK, name);
|
||||
__putname(name);
|
||||
if (!retval) {
|
||||
v9fs_refresh_inode(oldfid, d_inode(old_dentry));
|
||||
v9fs_invalidate_inode_attr(dir);
|
||||
}
|
||||
clunk_fid:
|
||||
p9_client_clunk(oldfid);
|
||||
return retval;
|
||||
}
|
||||
@ -1425,7 +1362,7 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rde
|
||||
{
|
||||
struct v9fs_session_info *v9ses = v9fs_inode2v9ses(dir);
|
||||
int retval;
|
||||
char *name;
|
||||
char name[2 + U32_MAX_DIGITS + 1 + U32_MAX_DIGITS + 1];
|
||||
u32 perm;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, " %lu,%pd mode: %hx MAJOR: %u MINOR: %u\n",
|
||||
@ -1435,26 +1372,16 @@ v9fs_vfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rde
|
||||
if (!new_valid_dev(rdev))
|
||||
return -EINVAL;
|
||||
|
||||
name = __getname();
|
||||
if (!name)
|
||||
return -ENOMEM;
|
||||
/* build extension */
|
||||
if (S_ISBLK(mode))
|
||||
sprintf(name, "b %u %u", MAJOR(rdev), MINOR(rdev));
|
||||
else if (S_ISCHR(mode))
|
||||
sprintf(name, "c %u %u", MAJOR(rdev), MINOR(rdev));
|
||||
else if (S_ISFIFO(mode))
|
||||
else
|
||||
*name = 0;
|
||||
else if (S_ISSOCK(mode))
|
||||
*name = 0;
|
||||
else {
|
||||
__putname(name);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
perm = unixmode2p9mode(v9ses, mode);
|
||||
retval = v9fs_vfs_mkspecial(dir, dentry, perm, name);
|
||||
__putname(name);
|
||||
|
||||
return retval;
|
||||
}
|
||||
@ -1530,7 +1457,7 @@ static const struct inode_operations v9fs_file_inode_operations = {
|
||||
static const struct inode_operations v9fs_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = v9fs_vfs_follow_link,
|
||||
.put_link = v9fs_vfs_put_link,
|
||||
.put_link = kfree_put_link,
|
||||
.getattr = v9fs_vfs_getattr,
|
||||
.setattr = v9fs_vfs_setattr,
|
||||
};
|
||||
|
@ -905,41 +905,24 @@ error:
|
||||
/**
|
||||
* v9fs_vfs_follow_link_dotl - follow a symlink path
|
||||
* @dentry: dentry for symlink
|
||||
* @nd: nameidata
|
||||
*
|
||||
* @cookie: place to pass the data to put_link()
|
||||
*/
|
||||
|
||||
static void *
|
||||
v9fs_vfs_follow_link_dotl(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *
|
||||
v9fs_vfs_follow_link_dotl(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
int retval;
|
||||
struct p9_fid *fid;
|
||||
char *link = __getname();
|
||||
struct p9_fid *fid = v9fs_fid_lookup(dentry);
|
||||
char *target;
|
||||
int retval;
|
||||
|
||||
p9_debug(P9_DEBUG_VFS, "%pd\n", dentry);
|
||||
|
||||
if (!link) {
|
||||
link = ERR_PTR(-ENOMEM);
|
||||
goto ndset;
|
||||
}
|
||||
fid = v9fs_fid_lookup(dentry);
|
||||
if (IS_ERR(fid)) {
|
||||
__putname(link);
|
||||
link = ERR_CAST(fid);
|
||||
goto ndset;
|
||||
}
|
||||
if (IS_ERR(fid))
|
||||
return ERR_CAST(fid);
|
||||
retval = p9_client_readlink(fid, &target);
|
||||
if (!retval) {
|
||||
strcpy(link, target);
|
||||
kfree(target);
|
||||
goto ndset;
|
||||
}
|
||||
__putname(link);
|
||||
link = ERR_PTR(retval);
|
||||
ndset:
|
||||
nd_set_link(nd, link);
|
||||
return NULL;
|
||||
if (retval)
|
||||
return ERR_PTR(retval);
|
||||
return *cookie = target;
|
||||
}
|
||||
|
||||
int v9fs_refresh_inode_dotl(struct p9_fid *fid, struct inode *inode)
|
||||
@ -1006,7 +989,7 @@ const struct inode_operations v9fs_file_inode_operations_dotl = {
|
||||
const struct inode_operations v9fs_symlink_inode_operations_dotl = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = v9fs_vfs_follow_link_dotl,
|
||||
.put_link = v9fs_vfs_put_link,
|
||||
.put_link = kfree_put_link,
|
||||
.getattr = v9fs_vfs_getattr_dotl,
|
||||
.setattr = v9fs_vfs_setattr_dotl,
|
||||
.setxattr = generic_setxattr,
|
||||
|
@ -12,14 +12,13 @@
|
||||
|
||||
#include "autofs_i.h"
|
||||
|
||||
static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *autofs4_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
|
||||
struct autofs_info *ino = autofs4_dentry_ino(dentry);
|
||||
if (ino && !autofs4_oz_mode(sbi))
|
||||
ino->last_used = jiffies;
|
||||
nd_set_link(nd, d_inode(dentry)->i_private);
|
||||
return NULL;
|
||||
return d_inode(dentry)->i_private;
|
||||
}
|
||||
|
||||
const struct inode_operations autofs4_symlink_inode_operations = {
|
||||
|
@ -42,8 +42,7 @@ 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);
|
||||
static void befs_destroy_inodecache(void);
|
||||
static void *befs_follow_link(struct dentry *, struct nameidata *);
|
||||
static void *befs_fast_follow_link(struct dentry *, struct nameidata *);
|
||||
static const char *befs_follow_link(struct dentry *, void **);
|
||||
static int befs_utf2nls(struct super_block *sb, const char *in, int in_len,
|
||||
char **out, int *out_len);
|
||||
static int befs_nls2utf(struct super_block *sb, const char *in, int in_len,
|
||||
@ -80,11 +79,6 @@ static const struct address_space_operations befs_aops = {
|
||||
.bmap = befs_bmap,
|
||||
};
|
||||
|
||||
static const struct inode_operations befs_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = befs_fast_follow_link,
|
||||
};
|
||||
|
||||
static const struct inode_operations befs_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = befs_follow_link,
|
||||
@ -403,10 +397,12 @@ static struct inode *befs_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_op = &befs_dir_inode_operations;
|
||||
inode->i_fop = &befs_dir_operations;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (befs_ino->i_flags & BEFS_LONG_SYMLINK)
|
||||
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
|
||||
inode->i_op = &befs_symlink_inode_operations;
|
||||
else
|
||||
inode->i_op = &befs_fast_symlink_inode_operations;
|
||||
} else {
|
||||
inode->i_link = befs_ino->i_data.symlink;
|
||||
inode->i_op = &simple_symlink_inode_operations;
|
||||
}
|
||||
} else {
|
||||
befs_error(sb, "Inode %lu is not a regular file, "
|
||||
"directory or symlink. THAT IS WRONG! BeFS has no "
|
||||
@ -467,8 +463,8 @@ befs_destroy_inodecache(void)
|
||||
* The data stream become link name. Unless the LONG_SYMLINK
|
||||
* flag is set.
|
||||
*/
|
||||
static void *
|
||||
befs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *
|
||||
befs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct super_block *sb = dentry->d_sb;
|
||||
struct befs_inode_info *befs_ino = BEFS_I(d_inode(dentry));
|
||||
@ -478,33 +474,20 @@ befs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
|
||||
if (len == 0) {
|
||||
befs_error(sb, "Long symlink with illegal length");
|
||||
link = ERR_PTR(-EIO);
|
||||
} else {
|
||||
befs_debug(sb, "Follow long symlink");
|
||||
|
||||
link = kmalloc(len, GFP_NOFS);
|
||||
if (!link) {
|
||||
link = ERR_PTR(-ENOMEM);
|
||||
} else if (befs_read_lsymlink(sb, data, link, len) != len) {
|
||||
kfree(link);
|
||||
befs_error(sb, "Failed to read entire long symlink");
|
||||
link = ERR_PTR(-EIO);
|
||||
} else {
|
||||
link[len - 1] = '\0';
|
||||
}
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
nd_set_link(nd, link);
|
||||
return NULL;
|
||||
}
|
||||
befs_debug(sb, "Follow long symlink");
|
||||
|
||||
|
||||
static void *
|
||||
befs_fast_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct befs_inode_info *befs_ino = BEFS_I(d_inode(dentry));
|
||||
|
||||
nd_set_link(nd, befs_ino->i_data.symlink);
|
||||
return NULL;
|
||||
link = kmalloc(len, GFP_NOFS);
|
||||
if (!link)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
if (befs_read_lsymlink(sb, data, link, len) != len) {
|
||||
kfree(link);
|
||||
befs_error(sb, "Failed to read entire long symlink");
|
||||
return ERR_PTR(-EIO);
|
||||
}
|
||||
link[len - 1] = '\0';
|
||||
return *cookie = link;
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -6,7 +6,6 @@
|
||||
#include <linux/string.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/writeback.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <linux/posix_acl.h>
|
||||
@ -819,6 +818,7 @@ static int fill_inode(struct inode *inode, struct page *locked_page,
|
||||
else
|
||||
kfree(sym); /* lost a race */
|
||||
}
|
||||
inode->i_link = ci->i_symlink;
|
||||
break;
|
||||
case S_IFDIR:
|
||||
inode->i_op = &ceph_dir_iops;
|
||||
@ -1691,16 +1691,9 @@ retry:
|
||||
/*
|
||||
* symlinks
|
||||
*/
|
||||
static void *ceph_sym_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ceph_inode_info *ci = ceph_inode(d_inode(dentry));
|
||||
nd_set_link(nd, ci->i_symlink);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static const struct inode_operations ceph_symlink_iops = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ceph_sym_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = ceph_setattr,
|
||||
.getattr = ceph_getattr,
|
||||
.setxattr = ceph_setxattr,
|
||||
|
@ -120,7 +120,7 @@ extern struct vfsmount *cifs_dfs_d_automount(struct path *path);
|
||||
#endif
|
||||
|
||||
/* Functions related to symlinks */
|
||||
extern void *cifs_follow_link(struct dentry *direntry, struct nameidata *nd);
|
||||
extern const char *cifs_follow_link(struct dentry *direntry, void **cookie);
|
||||
extern int cifs_readlink(struct dentry *direntry, char __user *buffer,
|
||||
int buflen);
|
||||
extern int cifs_symlink(struct inode *inode, struct dentry *direntry,
|
||||
|
@ -626,8 +626,8 @@ cifs_hl_exit:
|
||||
return rc;
|
||||
}
|
||||
|
||||
void *
|
||||
cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
const char *
|
||||
cifs_follow_link(struct dentry *direntry, void **cookie)
|
||||
{
|
||||
struct inode *inode = d_inode(direntry);
|
||||
int rc = -ENOMEM;
|
||||
@ -643,16 +643,18 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
|
||||
tlink = cifs_sb_tlink(cifs_sb);
|
||||
if (IS_ERR(tlink)) {
|
||||
rc = PTR_ERR(tlink);
|
||||
tlink = NULL;
|
||||
goto out;
|
||||
free_xid(xid);
|
||||
return ERR_CAST(tlink);
|
||||
}
|
||||
tcon = tlink_tcon(tlink);
|
||||
server = tcon->ses->server;
|
||||
|
||||
full_path = build_path_from_dentry(direntry);
|
||||
if (!full_path)
|
||||
goto out;
|
||||
if (!full_path) {
|
||||
free_xid(xid);
|
||||
cifs_put_tlink(tlink);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
cifs_dbg(FYI, "Full path: %s inode = 0x%p\n", full_path, inode);
|
||||
|
||||
@ -670,17 +672,13 @@ cifs_follow_link(struct dentry *direntry, struct nameidata *nd)
|
||||
&target_path, cifs_sb);
|
||||
|
||||
kfree(full_path);
|
||||
out:
|
||||
free_xid(xid);
|
||||
cifs_put_tlink(tlink);
|
||||
if (rc != 0) {
|
||||
kfree(target_path);
|
||||
target_path = ERR_PTR(rc);
|
||||
return ERR_PTR(rc);
|
||||
}
|
||||
|
||||
free_xid(xid);
|
||||
if (tlink)
|
||||
cifs_put_tlink(tlink);
|
||||
nd_set_link(nd, target_path);
|
||||
return NULL;
|
||||
return *cookie = target_path;
|
||||
}
|
||||
|
||||
int
|
||||
|
@ -279,36 +279,27 @@ static int configfs_getlink(struct dentry *dentry, char * path)
|
||||
|
||||
}
|
||||
|
||||
static void *configfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *configfs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
unsigned long page = get_zeroed_page(GFP_KERNEL);
|
||||
int error;
|
||||
|
||||
if (page) {
|
||||
error = configfs_getlink(dentry, (char *)page);
|
||||
if (!error) {
|
||||
nd_set_link(nd, (char *)page);
|
||||
return (void *)page;
|
||||
}
|
||||
if (!page)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
|
||||
error = configfs_getlink(dentry, (char *)page);
|
||||
if (!error) {
|
||||
return *cookie = (void *)page;
|
||||
}
|
||||
|
||||
nd_set_link(nd, ERR_PTR(error));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void configfs_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *cookie)
|
||||
{
|
||||
if (cookie) {
|
||||
unsigned long page = (unsigned long)cookie;
|
||||
free_page(page);
|
||||
}
|
||||
free_page(page);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
const struct inode_operations configfs_symlink_inode_operations = {
|
||||
.follow_link = configfs_follow_link,
|
||||
.readlink = generic_readlink,
|
||||
.put_link = configfs_put_link,
|
||||
.put_link = free_page_put_link,
|
||||
.setattr = configfs_setattr,
|
||||
};
|
||||
|
||||
|
@ -17,7 +17,6 @@
|
||||
#include <linux/fs.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/slab.h>
|
||||
@ -43,17 +42,6 @@ const struct file_operations debugfs_file_operations = {
|
||||
.llseek = noop_llseek,
|
||||
};
|
||||
|
||||
static void *debugfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
nd_set_link(nd, d_inode(dentry)->i_private);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations debugfs_link_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = debugfs_follow_link,
|
||||
};
|
||||
|
||||
static int debugfs_u8_set(void *data, u64 val)
|
||||
{
|
||||
*(u8 *)data = val;
|
||||
|
@ -174,7 +174,7 @@ static void debugfs_evict_inode(struct inode *inode)
|
||||
truncate_inode_pages_final(&inode->i_data);
|
||||
clear_inode(inode);
|
||||
if (S_ISLNK(inode->i_mode))
|
||||
kfree(inode->i_private);
|
||||
kfree(inode->i_link);
|
||||
}
|
||||
|
||||
static const struct super_operations debugfs_super_operations = {
|
||||
@ -511,8 +511,8 @@ struct dentry *debugfs_create_symlink(const char *name, struct dentry *parent,
|
||||
return failed_creating(dentry);
|
||||
}
|
||||
inode->i_mode = S_IFLNK | S_IRWXUGO;
|
||||
inode->i_op = &debugfs_link_operations;
|
||||
inode->i_private = link;
|
||||
inode->i_op = &simple_symlink_inode_operations;
|
||||
inode->i_link = link;
|
||||
d_instantiate(dentry, inode);
|
||||
return end_creating(dentry);
|
||||
}
|
||||
|
@ -170,7 +170,6 @@ out_unlock:
|
||||
* @directory_inode: inode of the new file's dentry's parent in ecryptfs
|
||||
* @ecryptfs_dentry: New file's dentry in ecryptfs
|
||||
* @mode: The mode of the new file
|
||||
* @nd: nameidata of ecryptfs' parent's dentry & vfsmount
|
||||
*
|
||||
* Creates the underlying file and the eCryptfs inode which will link to
|
||||
* it. It will also update the eCryptfs directory inode to mimic the
|
||||
@ -384,7 +383,7 @@ static int ecryptfs_lookup_interpose(struct dentry *dentry,
|
||||
* ecryptfs_lookup
|
||||
* @ecryptfs_dir_inode: The eCryptfs directory inode
|
||||
* @ecryptfs_dentry: The eCryptfs dentry that we are looking up
|
||||
* @ecryptfs_nd: nameidata; may be NULL
|
||||
* @flags: lookup flags
|
||||
*
|
||||
* Find a file on disk. If the file does not exist, then we'll add it to the
|
||||
* dentry cache and continue on to read it from the disk.
|
||||
@ -675,18 +674,16 @@ out:
|
||||
return rc ? ERR_PTR(rc) : buf;
|
||||
}
|
||||
|
||||
static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *ecryptfs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
size_t len;
|
||||
char *buf = ecryptfs_readlink_lower(dentry, &len);
|
||||
if (IS_ERR(buf))
|
||||
goto out;
|
||||
return buf;
|
||||
fsstack_copy_attr_atime(d_inode(dentry),
|
||||
d_inode(ecryptfs_dentry_to_lower(dentry)));
|
||||
buf[len] = '\0';
|
||||
out:
|
||||
nd_set_link(nd, buf);
|
||||
return NULL;
|
||||
return *cookie = buf;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -16,5 +16,5 @@
|
||||
libore-y := ore.o ore_raid.o
|
||||
obj-$(CONFIG_ORE) += libore.o
|
||||
|
||||
exofs-y := inode.o file.o symlink.o namei.o dir.o super.o sys.o
|
||||
exofs-y := inode.o file.o namei.o dir.o super.o sys.o
|
||||
obj-$(CONFIG_EXOFS_FS) += exofs.o
|
||||
|
@ -207,10 +207,6 @@ extern const struct address_space_operations exofs_aops;
|
||||
extern const struct inode_operations exofs_dir_inode_operations;
|
||||
extern const struct inode_operations exofs_special_inode_operations;
|
||||
|
||||
/* symlink.c */
|
||||
extern const struct inode_operations exofs_symlink_inode_operations;
|
||||
extern const struct inode_operations exofs_fast_symlink_inode_operations;
|
||||
|
||||
/* exofs_init_comps will initialize an ore_components device array
|
||||
* pointing to a single ore_comp struct, and a round-robin view
|
||||
* of the device table.
|
||||
|
@ -1222,10 +1222,11 @@ struct inode *exofs_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_fop = &exofs_dir_operations;
|
||||
inode->i_mapping->a_ops = &exofs_aops;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (exofs_inode_is_fast_symlink(inode))
|
||||
inode->i_op = &exofs_fast_symlink_inode_operations;
|
||||
else {
|
||||
inode->i_op = &exofs_symlink_inode_operations;
|
||||
if (exofs_inode_is_fast_symlink(inode)) {
|
||||
inode->i_op = &simple_symlink_inode_operations;
|
||||
inode->i_link = (char *)oi->i_data;
|
||||
} else {
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_mapping->a_ops = &exofs_aops;
|
||||
}
|
||||
} else {
|
||||
|
@ -113,7 +113,7 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
oi = exofs_i(inode);
|
||||
if (l > sizeof(oi->i_data)) {
|
||||
/* slow symlink */
|
||||
inode->i_op = &exofs_symlink_inode_operations;
|
||||
inode->i_op = &page_symlink_inode_operations;
|
||||
inode->i_mapping->a_ops = &exofs_aops;
|
||||
memset(oi->i_data, 0, sizeof(oi->i_data));
|
||||
|
||||
@ -122,7 +122,8 @@ static int exofs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
goto out_fail;
|
||||
} else {
|
||||
/* fast symlink */
|
||||
inode->i_op = &exofs_fast_symlink_inode_operations;
|
||||
inode->i_op = &simple_symlink_inode_operations;
|
||||
inode->i_link = (char *)oi->i_data;
|
||||
memcpy(oi->i_data, symname, l);
|
||||
inode->i_size = l-1;
|
||||
}
|
||||
|
@ -1,55 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2005, 2006
|
||||
* Avishay Traeger (avishay@gmail.com)
|
||||
* Copyright (C) 2008, 2009
|
||||
* Boaz Harrosh <ooo@electrozaur.com>
|
||||
*
|
||||
* Copyrights for code taken from ext2:
|
||||
* Copyright (C) 1992, 1993, 1994, 1995
|
||||
* Remy Card (card@masi.ibp.fr)
|
||||
* Laboratoire MASI - Institut Blaise Pascal
|
||||
* Universite Pierre et Marie Curie (Paris VI)
|
||||
* from
|
||||
* linux/fs/minix/inode.c
|
||||
* Copyright (C) 1991, 1992 Linus Torvalds
|
||||
*
|
||||
* This file is part of exofs.
|
||||
*
|
||||
* exofs is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation. Since it is based on ext2, and the only
|
||||
* valid version of GPL for the Linux kernel is version 2, the only valid
|
||||
* version of GPL for exofs is version 2.
|
||||
*
|
||||
* exofs is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with exofs; if not, write to the Free Software
|
||||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "exofs.h"
|
||||
|
||||
static void *exofs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct exofs_i_info *oi = exofs_i(d_inode(dentry));
|
||||
|
||||
nd_set_link(nd, (char *)oi->i_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations exofs_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = page_follow_link_light,
|
||||
.put_link = page_put_link,
|
||||
};
|
||||
|
||||
const struct inode_operations exofs_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = exofs_follow_link,
|
||||
};
|
@ -1403,6 +1403,7 @@ struct inode *ext2_iget (struct super_block *sb, unsigned long ino)
|
||||
inode->i_mapping->a_ops = &ext2_aops;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (ext2_inode_is_fast_symlink(inode)) {
|
||||
inode->i_link = (char *)ei->i_data;
|
||||
inode->i_op = &ext2_fast_symlink_inode_operations;
|
||||
nd_terminate_link(ei->i_data, inode->i_size,
|
||||
sizeof(ei->i_data) - 1);
|
||||
|
@ -189,7 +189,8 @@ static int ext2_symlink (struct inode * dir, struct dentry * dentry,
|
||||
} else {
|
||||
/* fast symlink */
|
||||
inode->i_op = &ext2_fast_symlink_inode_operations;
|
||||
memcpy((char*)(EXT2_I(inode)->i_data),symname,l);
|
||||
inode->i_link = (char*)EXT2_I(inode)->i_data;
|
||||
memcpy(inode->i_link, symname, l);
|
||||
inode->i_size = l-1;
|
||||
}
|
||||
mark_inode_dirty(inode);
|
||||
|
@ -19,14 +19,6 @@
|
||||
|
||||
#include "ext2.h"
|
||||
#include "xattr.h"
|
||||
#include <linux/namei.h>
|
||||
|
||||
static void *ext2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ext2_inode_info *ei = EXT2_I(d_inode(dentry));
|
||||
nd_set_link(nd, (char *)ei->i_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations ext2_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
@ -43,7 +35,7 @@ const struct inode_operations ext2_symlink_inode_operations = {
|
||||
|
||||
const struct inode_operations ext2_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ext2_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = ext2_setattr,
|
||||
#ifdef CONFIG_EXT2_FS_XATTR
|
||||
.setxattr = generic_setxattr,
|
||||
|
@ -2999,6 +2999,7 @@ struct inode *ext3_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_op = &ext3_fast_symlink_inode_operations;
|
||||
nd_terminate_link(ei->i_data, inode->i_size,
|
||||
sizeof(ei->i_data) - 1);
|
||||
inode->i_link = (char *)ei->i_data;
|
||||
} else {
|
||||
inode->i_op = &ext3_symlink_inode_operations;
|
||||
ext3_set_aops(inode);
|
||||
|
@ -2308,7 +2308,8 @@ retry:
|
||||
}
|
||||
} else {
|
||||
inode->i_op = &ext3_fast_symlink_inode_operations;
|
||||
memcpy((char*)&EXT3_I(inode)->i_data,symname,l);
|
||||
inode->i_link = (char*)&EXT3_I(inode)->i_data;
|
||||
memcpy(inode->i_link, symname, l);
|
||||
inode->i_size = l-1;
|
||||
}
|
||||
EXT3_I(inode)->i_disksize = inode->i_size;
|
||||
|
@ -17,17 +17,9 @@
|
||||
* ext3 symlink handling code
|
||||
*/
|
||||
|
||||
#include <linux/namei.h>
|
||||
#include "ext3.h"
|
||||
#include "xattr.h"
|
||||
|
||||
static void * ext3_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ext3_inode_info *ei = EXT3_I(d_inode(dentry));
|
||||
nd_set_link(nd, (char*)ei->i_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations ext3_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = page_follow_link_light,
|
||||
@ -43,7 +35,7 @@ const struct inode_operations ext3_symlink_inode_operations = {
|
||||
|
||||
const struct inode_operations ext3_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ext3_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = ext3_setattr,
|
||||
#ifdef CONFIG_EXT3_FS_XATTR
|
||||
.setxattr = generic_setxattr,
|
||||
|
@ -2847,6 +2847,7 @@ extern int ext4_mpage_readpages(struct address_space *mapping,
|
||||
unsigned nr_pages);
|
||||
|
||||
/* symlink.c */
|
||||
extern const struct inode_operations ext4_encrypted_symlink_inode_operations;
|
||||
extern const struct inode_operations ext4_symlink_inode_operations;
|
||||
extern const struct inode_operations ext4_fast_symlink_inode_operations;
|
||||
|
||||
|
@ -4213,8 +4213,11 @@ struct inode *ext4_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_op = &ext4_dir_inode_operations;
|
||||
inode->i_fop = &ext4_dir_operations;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (ext4_inode_is_fast_symlink(inode) &&
|
||||
!ext4_encrypted_inode(inode)) {
|
||||
if (ext4_encrypted_inode(inode)) {
|
||||
inode->i_op = &ext4_encrypted_symlink_inode_operations;
|
||||
ext4_set_aops(inode);
|
||||
} else if (ext4_inode_is_fast_symlink(inode)) {
|
||||
inode->i_link = (char *)ei->i_data;
|
||||
inode->i_op = &ext4_fast_symlink_inode_operations;
|
||||
nd_terminate_link(ei->i_data, inode->i_size,
|
||||
sizeof(ei->i_data) - 1);
|
||||
|
@ -3206,10 +3206,12 @@ static int ext4_symlink(struct inode *dir,
|
||||
goto err_drop_inode;
|
||||
sd->len = cpu_to_le16(ostr.len);
|
||||
disk_link.name = (char *) sd;
|
||||
inode->i_op = &ext4_encrypted_symlink_inode_operations;
|
||||
}
|
||||
|
||||
if ((disk_link.len > EXT4_N_BLOCKS * 4)) {
|
||||
inode->i_op = &ext4_symlink_inode_operations;
|
||||
if (!encryption_required)
|
||||
inode->i_op = &ext4_symlink_inode_operations;
|
||||
ext4_set_aops(inode);
|
||||
/*
|
||||
* We cannot call page_symlink() with transaction started
|
||||
@ -3249,9 +3251,10 @@ static int ext4_symlink(struct inode *dir,
|
||||
} else {
|
||||
/* clear the extent format for fast symlink */
|
||||
ext4_clear_inode_flag(inode, EXT4_INODE_EXTENTS);
|
||||
inode->i_op = encryption_required ?
|
||||
&ext4_symlink_inode_operations :
|
||||
&ext4_fast_symlink_inode_operations;
|
||||
if (!encryption_required) {
|
||||
inode->i_op = &ext4_fast_symlink_inode_operations;
|
||||
inode->i_link = (char *)&EXT4_I(inode)->i_data;
|
||||
}
|
||||
memcpy((char *)&EXT4_I(inode)->i_data, disk_link.name,
|
||||
disk_link.len);
|
||||
inode->i_size = disk_link.len - 1;
|
||||
|
@ -23,7 +23,7 @@
|
||||
#include "xattr.h"
|
||||
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *ext4_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct page *cpage = NULL;
|
||||
char *caddr, *paddr = NULL;
|
||||
@ -35,12 +35,9 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
int res;
|
||||
u32 plen, max_size = inode->i_sb->s_blocksize;
|
||||
|
||||
if (!ext4_encrypted_inode(inode))
|
||||
return page_follow_link_light(dentry, nd);
|
||||
|
||||
ctx = ext4_get_fname_crypto_ctx(inode, inode->i_sb->s_blocksize);
|
||||
if (IS_ERR(ctx))
|
||||
return ctx;
|
||||
return ERR_CAST(ctx);
|
||||
|
||||
if (ext4_inode_is_fast_symlink(inode)) {
|
||||
caddr = (char *) EXT4_I(inode)->i_data;
|
||||
@ -49,7 +46,7 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
cpage = read_mapping_page(inode->i_mapping, 0, NULL);
|
||||
if (IS_ERR(cpage)) {
|
||||
ext4_put_fname_crypto_ctx(&ctx);
|
||||
return cpage;
|
||||
return ERR_CAST(cpage);
|
||||
}
|
||||
caddr = kmap(cpage);
|
||||
caddr[size] = 0;
|
||||
@ -80,13 +77,12 @@ static void *ext4_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
/* Null-terminate the name */
|
||||
if (res <= plen)
|
||||
paddr[res] = '\0';
|
||||
nd_set_link(nd, paddr);
|
||||
ext4_put_fname_crypto_ctx(&ctx);
|
||||
if (cpage) {
|
||||
kunmap(cpage);
|
||||
page_cache_release(cpage);
|
||||
}
|
||||
return NULL;
|
||||
return *cookie = paddr;
|
||||
errout:
|
||||
ext4_put_fname_crypto_ctx(&ctx);
|
||||
if (cpage) {
|
||||
@ -97,36 +93,22 @@ errout:
|
||||
return ERR_PTR(res);
|
||||
}
|
||||
|
||||
static void ext4_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *cookie)
|
||||
{
|
||||
struct page *page = cookie;
|
||||
|
||||
if (!page) {
|
||||
kfree(nd_get_link(nd));
|
||||
} else {
|
||||
kunmap(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
}
|
||||
const struct inode_operations ext4_encrypted_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ext4_follow_link,
|
||||
.put_link = kfree_put_link,
|
||||
.setattr = ext4_setattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
.listxattr = ext4_listxattr,
|
||||
.removexattr = generic_removexattr,
|
||||
};
|
||||
#endif
|
||||
|
||||
static void *ext4_follow_fast_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ext4_inode_info *ei = EXT4_I(d_inode(dentry));
|
||||
nd_set_link(nd, (char *) ei->i_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations ext4_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
#ifdef CONFIG_EXT4_FS_ENCRYPTION
|
||||
.follow_link = ext4_follow_link,
|
||||
.put_link = ext4_put_link,
|
||||
#else
|
||||
.follow_link = page_follow_link_light,
|
||||
.put_link = page_put_link,
|
||||
#endif
|
||||
.setattr = ext4_setattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
@ -136,7 +118,7 @@ const struct inode_operations ext4_symlink_inode_operations = {
|
||||
|
||||
const struct inode_operations ext4_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ext4_follow_fast_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = ext4_setattr,
|
||||
.setxattr = generic_setxattr,
|
||||
.getxattr = generic_getxattr,
|
||||
|
@ -296,19 +296,15 @@ fail:
|
||||
return err;
|
||||
}
|
||||
|
||||
static void *f2fs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *f2fs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct page *page = page_follow_link_light(dentry, nd);
|
||||
|
||||
if (IS_ERR_OR_NULL(page))
|
||||
return page;
|
||||
|
||||
/* this is broken symlink case */
|
||||
if (*nd_get_link(nd) == 0) {
|
||||
page_put_link(dentry, nd, page);
|
||||
return ERR_PTR(-ENOENT);
|
||||
const char *link = page_follow_link_light(dentry, cookie);
|
||||
if (!IS_ERR(link) && !*link) {
|
||||
/* this is broken symlink case */
|
||||
page_put_link(NULL, *cookie);
|
||||
link = ERR_PTR(-ENOENT);
|
||||
}
|
||||
return page;
|
||||
return link;
|
||||
}
|
||||
|
||||
static int f2fs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
|
@ -50,9 +50,6 @@ extern daddr_t vxfs_bmap1(struct inode *, long);
|
||||
/* vxfs_fshead.c */
|
||||
extern int vxfs_read_fshead(struct super_block *);
|
||||
|
||||
/* vxfs_immed.c */
|
||||
extern const struct inode_operations vxfs_immed_symlink_iops;
|
||||
|
||||
/* vxfs_inode.c */
|
||||
extern const struct address_space_operations vxfs_immed_aops;
|
||||
extern struct kmem_cache *vxfs_inode_cachep;
|
||||
|
@ -32,28 +32,14 @@
|
||||
*/
|
||||
#include <linux/fs.h>
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "vxfs.h"
|
||||
#include "vxfs_extern.h"
|
||||
#include "vxfs_inode.h"
|
||||
|
||||
|
||||
static void * vxfs_immed_follow_link(struct dentry *, struct nameidata *);
|
||||
|
||||
static int vxfs_immed_readpage(struct file *, struct page *);
|
||||
|
||||
/*
|
||||
* Inode operations for immed symlinks.
|
||||
*
|
||||
* Unliked all other operations we do not go through the pagecache,
|
||||
* but do all work directly on the inode.
|
||||
*/
|
||||
const struct inode_operations vxfs_immed_symlink_iops = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = vxfs_immed_follow_link,
|
||||
};
|
||||
|
||||
/*
|
||||
* Address space operations for immed files and directories.
|
||||
*/
|
||||
@ -61,26 +47,6 @@ const struct address_space_operations vxfs_immed_aops = {
|
||||
.readpage = vxfs_immed_readpage,
|
||||
};
|
||||
|
||||
/**
|
||||
* vxfs_immed_follow_link - follow immed symlink
|
||||
* @dp: dentry for the link
|
||||
* @np: pathname lookup data for the current path walk
|
||||
*
|
||||
* Description:
|
||||
* vxfs_immed_follow_link restarts the pathname lookup with
|
||||
* the data obtained from @dp.
|
||||
*
|
||||
* Returns:
|
||||
* Zero on success, else a negative error code.
|
||||
*/
|
||||
static void *
|
||||
vxfs_immed_follow_link(struct dentry *dp, struct nameidata *np)
|
||||
{
|
||||
struct vxfs_inode_info *vip = VXFS_INO(d_inode(dp));
|
||||
nd_set_link(np, vip->vii_immed.vi_immed);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* vxfs_immed_readpage - read part of an immed inode into pagecache
|
||||
* @file: file context (unused)
|
||||
|
@ -35,6 +35,7 @@
|
||||
#include <linux/pagemap.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "vxfs.h"
|
||||
#include "vxfs_inode.h"
|
||||
@ -327,8 +328,10 @@ vxfs_iget(struct super_block *sbp, ino_t ino)
|
||||
ip->i_op = &page_symlink_inode_operations;
|
||||
ip->i_mapping->a_ops = &vxfs_aops;
|
||||
} else {
|
||||
ip->i_op = &vxfs_immed_symlink_iops;
|
||||
vip->vii_immed.vi_immed[ip->i_size] = '\0';
|
||||
ip->i_op = &simple_symlink_inode_operations;
|
||||
ip->i_link = vip->vii_immed.vi_immed;
|
||||
nd_terminate_link(ip->i_link, ip->i_size,
|
||||
sizeof(vip->vii_immed.vi_immed) - 1);
|
||||
}
|
||||
} else
|
||||
init_special_inode(ip, ip->i_mode, old_decode_dev(vip->vii_rdev));
|
||||
|
@ -1365,7 +1365,7 @@ static int fuse_readdir(struct file *file, struct dir_context *ctx)
|
||||
return err;
|
||||
}
|
||||
|
||||
static char *read_link(struct dentry *dentry)
|
||||
static const char *fuse_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct fuse_conn *fc = get_fuse_conn(inode);
|
||||
@ -1389,28 +1389,12 @@ static char *read_link(struct dentry *dentry)
|
||||
link = ERR_PTR(ret);
|
||||
} else {
|
||||
link[ret] = '\0';
|
||||
*cookie = link;
|
||||
}
|
||||
fuse_invalidate_atime(inode);
|
||||
return link;
|
||||
}
|
||||
|
||||
static void free_link(char *link)
|
||||
{
|
||||
if (!IS_ERR(link))
|
||||
free_page((unsigned long) link);
|
||||
}
|
||||
|
||||
static void *fuse_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
nd_set_link(nd, read_link(dentry));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void fuse_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
|
||||
{
|
||||
free_link(nd_get_link(nd));
|
||||
}
|
||||
|
||||
static int fuse_dir_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
return fuse_open_common(inode, file, true);
|
||||
@ -1926,7 +1910,7 @@ static const struct inode_operations fuse_common_inode_operations = {
|
||||
static const struct inode_operations fuse_symlink_inode_operations = {
|
||||
.setattr = fuse_setattr,
|
||||
.follow_link = fuse_follow_link,
|
||||
.put_link = fuse_put_link,
|
||||
.put_link = free_page_put_link,
|
||||
.readlink = generic_readlink,
|
||||
.getattr = fuse_getattr,
|
||||
.setxattr = fuse_setxattr,
|
||||
|
@ -1548,7 +1548,7 @@ out:
|
||||
* Returns: 0 on success or error code
|
||||
*/
|
||||
|
||||
static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *gfs2_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct gfs2_inode *ip = GFS2_I(d_inode(dentry));
|
||||
struct gfs2_holder i_gh;
|
||||
@ -1561,8 +1561,7 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
error = gfs2_glock_nq(&i_gh);
|
||||
if (error) {
|
||||
gfs2_holder_uninit(&i_gh);
|
||||
nd_set_link(nd, ERR_PTR(error));
|
||||
return NULL;
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
size = (unsigned int)i_size_read(&ip->i_inode);
|
||||
@ -1586,8 +1585,9 @@ static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
brelse(dibh);
|
||||
out:
|
||||
gfs2_glock_dq_uninit(&i_gh);
|
||||
nd_set_link(nd, buf);
|
||||
return NULL;
|
||||
if (!IS_ERR(buf))
|
||||
*cookie = buf;
|
||||
return buf;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -892,7 +892,7 @@ static const struct inode_operations hostfs_dir_iops = {
|
||||
.setattr = hostfs_setattr,
|
||||
};
|
||||
|
||||
static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *hostfs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
char *link = __getname();
|
||||
if (link) {
|
||||
@ -906,21 +906,18 @@ static void *hostfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
}
|
||||
if (err < 0) {
|
||||
__putname(link);
|
||||
link = ERR_PTR(err);
|
||||
return ERR_PTR(err);
|
||||
}
|
||||
} else {
|
||||
link = ERR_PTR(-ENOMEM);
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
|
||||
nd_set_link(nd, link);
|
||||
return NULL;
|
||||
return *cookie = link;
|
||||
}
|
||||
|
||||
static void hostfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
|
||||
static void hostfs_put_link(struct inode *unused, void *cookie)
|
||||
{
|
||||
char *s = nd_get_link(nd);
|
||||
if (!IS_ERR(s))
|
||||
__putname(s);
|
||||
__putname(cookie);
|
||||
}
|
||||
|
||||
static const struct inode_operations hostfs_link_iops = {
|
||||
|
@ -642,20 +642,19 @@ static int hppfs_readlink(struct dentry *dentry, char __user *buffer,
|
||||
buflen);
|
||||
}
|
||||
|
||||
static void *hppfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *hppfs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry;
|
||||
|
||||
return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, nd);
|
||||
return d_inode(proc_dentry)->i_op->follow_link(proc_dentry, cookie);
|
||||
}
|
||||
|
||||
static void hppfs_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *cookie)
|
||||
static void hppfs_put_link(struct inode *inode, void *cookie)
|
||||
{
|
||||
struct dentry *proc_dentry = HPPFS_I(d_inode(dentry))->proc_dentry;
|
||||
struct inode *proc_inode = d_inode(HPPFS_I(inode)->proc_dentry);
|
||||
|
||||
if (d_inode(proc_dentry)->i_op->put_link)
|
||||
d_inode(proc_dentry)->i_op->put_link(proc_dentry, nd, cookie);
|
||||
if (proc_inode->i_op->put_link)
|
||||
proc_inode->i_op->put_link(proc_inode, cookie);
|
||||
}
|
||||
|
||||
static const struct inode_operations hppfs_dir_iops = {
|
||||
|
51
fs/inode.c
51
fs/inode.c
@ -152,6 +152,7 @@ int inode_init_always(struct super_block *sb, struct inode *inode)
|
||||
inode->i_pipe = NULL;
|
||||
inode->i_bdev = NULL;
|
||||
inode->i_cdev = NULL;
|
||||
inode->i_link = NULL;
|
||||
inode->i_rdev = 0;
|
||||
inode->dirtied_when = 0;
|
||||
|
||||
@ -1584,36 +1585,47 @@ static int update_time(struct inode *inode, struct timespec *time, int flags)
|
||||
* This function automatically handles read only file systems and media,
|
||||
* as well as the "noatime" flag and inode specific "noatime" markers.
|
||||
*/
|
||||
bool atime_needs_update(const struct path *path, struct inode *inode)
|
||||
{
|
||||
struct vfsmount *mnt = path->mnt;
|
||||
struct timespec now;
|
||||
|
||||
if (inode->i_flags & S_NOATIME)
|
||||
return false;
|
||||
if (IS_NOATIME(inode))
|
||||
return false;
|
||||
if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
|
||||
return false;
|
||||
|
||||
if (mnt->mnt_flags & MNT_NOATIME)
|
||||
return false;
|
||||
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
|
||||
return false;
|
||||
|
||||
now = current_fs_time(inode->i_sb);
|
||||
|
||||
if (!relatime_need_update(mnt, inode, now))
|
||||
return false;
|
||||
|
||||
if (timespec_equal(&inode->i_atime, &now))
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void touch_atime(const struct path *path)
|
||||
{
|
||||
struct vfsmount *mnt = path->mnt;
|
||||
struct inode *inode = d_inode(path->dentry);
|
||||
struct timespec now;
|
||||
|
||||
if (inode->i_flags & S_NOATIME)
|
||||
return;
|
||||
if (IS_NOATIME(inode))
|
||||
return;
|
||||
if ((inode->i_sb->s_flags & MS_NODIRATIME) && S_ISDIR(inode->i_mode))
|
||||
return;
|
||||
|
||||
if (mnt->mnt_flags & MNT_NOATIME)
|
||||
return;
|
||||
if ((mnt->mnt_flags & MNT_NODIRATIME) && S_ISDIR(inode->i_mode))
|
||||
return;
|
||||
|
||||
now = current_fs_time(inode->i_sb);
|
||||
|
||||
if (!relatime_need_update(mnt, inode, now))
|
||||
return;
|
||||
|
||||
if (timespec_equal(&inode->i_atime, &now))
|
||||
if (!atime_needs_update(path, inode))
|
||||
return;
|
||||
|
||||
if (!sb_start_write_trylock(inode->i_sb))
|
||||
return;
|
||||
|
||||
if (__mnt_want_write(mnt))
|
||||
if (__mnt_want_write(mnt) != 0)
|
||||
goto skip_update;
|
||||
/*
|
||||
* File systems can error out when updating inodes if they need to
|
||||
@ -1624,6 +1636,7 @@ void touch_atime(const struct path *path)
|
||||
* We may also fail on filesystems that have the ability to make parts
|
||||
* of the fs read only, e.g. subvolumes in Btrfs.
|
||||
*/
|
||||
now = current_fs_time(inode->i_sb);
|
||||
update_time(inode, &now, S_ATIME);
|
||||
__mnt_drop_write(mnt);
|
||||
skip_update:
|
||||
|
@ -354,6 +354,7 @@ static int jffs2_symlink (struct inode *dir_i, struct dentry *dentry, const char
|
||||
ret = -ENOMEM;
|
||||
goto fail;
|
||||
}
|
||||
inode->i_link = f->target;
|
||||
|
||||
jffs2_dbg(1, "%s(): symlink's target '%s' cached\n",
|
||||
__func__, (char *)f->target);
|
||||
|
@ -294,6 +294,7 @@ struct inode *jffs2_iget(struct super_block *sb, unsigned long ino)
|
||||
|
||||
case S_IFLNK:
|
||||
inode->i_op = &jffs2_symlink_inode_operations;
|
||||
inode->i_link = f->target;
|
||||
break;
|
||||
|
||||
case S_IFDIR:
|
||||
|
@ -9,58 +9,15 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
|
||||
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include "nodelist.h"
|
||||
|
||||
static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd);
|
||||
|
||||
const struct inode_operations jffs2_symlink_inode_operations =
|
||||
{
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = jffs2_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = jffs2_setattr,
|
||||
.setxattr = jffs2_setxattr,
|
||||
.getxattr = jffs2_getxattr,
|
||||
.listxattr = jffs2_listxattr,
|
||||
.removexattr = jffs2_removexattr
|
||||
};
|
||||
|
||||
static void *jffs2_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct jffs2_inode_info *f = JFFS2_INODE_INFO(d_inode(dentry));
|
||||
char *p = (char *)f->target;
|
||||
|
||||
/*
|
||||
* We don't acquire the f->sem mutex here since the only data we
|
||||
* use is f->target.
|
||||
*
|
||||
* 1. If we are here the inode has already built and f->target has
|
||||
* to point to the target path.
|
||||
* 2. Nobody uses f->target (if the inode is symlink's inode). The
|
||||
* exception is inode freeing function which frees f->target. But
|
||||
* it can't be called while we are here and before VFS has
|
||||
* stopped using our f->target string which we provide by means of
|
||||
* nd_set_link() call.
|
||||
*/
|
||||
|
||||
if (!p) {
|
||||
pr_err("%s(): can't find symlink target\n", __func__);
|
||||
p = ERR_PTR(-EIO);
|
||||
}
|
||||
jffs2_dbg(1, "%s(): target path is '%s'\n",
|
||||
__func__, (char *)f->target);
|
||||
|
||||
nd_set_link(nd, p);
|
||||
|
||||
/*
|
||||
* We will unlock the f->sem mutex but VFS will use the f->target string. This is safe
|
||||
* since the only way that may cause f->target to be changed is iput() operation.
|
||||
* But VFS will not use f->target after iput() has been called.
|
||||
*/
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -63,11 +63,12 @@ struct inode *jfs_iget(struct super_block *sb, unsigned long ino)
|
||||
inode->i_mapping->a_ops = &jfs_aops;
|
||||
} else {
|
||||
inode->i_op = &jfs_fast_symlink_inode_operations;
|
||||
inode->i_link = JFS_IP(inode)->i_inline;
|
||||
/*
|
||||
* The inline data should be null-terminated, but
|
||||
* don't let on-disk corruption crash the kernel
|
||||
*/
|
||||
JFS_IP(inode)->i_inline[inode->i_size] = '\0';
|
||||
inode->i_link[inode->i_size] = '\0';
|
||||
}
|
||||
} else {
|
||||
inode->i_op = &jfs_file_inode_operations;
|
||||
|
@ -880,7 +880,6 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
|
||||
int ssize; /* source pathname size */
|
||||
struct btstack btstack;
|
||||
struct inode *ip = d_inode(dentry);
|
||||
unchar *i_fastsymlink;
|
||||
s64 xlen = 0;
|
||||
int bmask = 0, xsize;
|
||||
s64 xaddr;
|
||||
@ -946,8 +945,8 @@ static int jfs_symlink(struct inode *dip, struct dentry *dentry,
|
||||
if (ssize <= IDATASIZE) {
|
||||
ip->i_op = &jfs_fast_symlink_inode_operations;
|
||||
|
||||
i_fastsymlink = JFS_IP(ip)->i_inline;
|
||||
memcpy(i_fastsymlink, name, ssize);
|
||||
ip->i_link = JFS_IP(ip)->i_inline;
|
||||
memcpy(ip->i_link, name, ssize);
|
||||
ip->i_size = ssize - 1;
|
||||
|
||||
/*
|
||||
|
@ -17,21 +17,13 @@
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
#include "jfs_incore.h"
|
||||
#include "jfs_inode.h"
|
||||
#include "jfs_xattr.h"
|
||||
|
||||
static void *jfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
char *s = JFS_IP(d_inode(dentry))->i_inline;
|
||||
nd_set_link(nd, s);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations jfs_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = jfs_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = jfs_setattr,
|
||||
.setxattr = jfs_setxattr,
|
||||
.getxattr = jfs_getxattr,
|
||||
|
@ -112,25 +112,18 @@ static int kernfs_getlink(struct dentry *dentry, char *path)
|
||||
return error;
|
||||
}
|
||||
|
||||
static void *kernfs_iop_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *kernfs_iop_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
int error = -ENOMEM;
|
||||
unsigned long page = get_zeroed_page(GFP_KERNEL);
|
||||
if (page) {
|
||||
error = kernfs_getlink(dentry, (char *) page);
|
||||
if (error < 0)
|
||||
free_page((unsigned long)page);
|
||||
}
|
||||
nd_set_link(nd, error ? ERR_PTR(error) : (char *)page);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void kernfs_iop_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *cookie)
|
||||
{
|
||||
char *page = nd_get_link(nd);
|
||||
if (!IS_ERR(page))
|
||||
if (!page)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
error = kernfs_getlink(dentry, (char *)page);
|
||||
if (unlikely(error < 0)) {
|
||||
free_page((unsigned long)page);
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
return *cookie = (char *)page;
|
||||
}
|
||||
|
||||
const struct inode_operations kernfs_symlink_iops = {
|
||||
@ -140,7 +133,7 @@ const struct inode_operations kernfs_symlink_iops = {
|
||||
.listxattr = kernfs_iop_listxattr,
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = kernfs_iop_follow_link,
|
||||
.put_link = kernfs_iop_put_link,
|
||||
.put_link = free_page_put_link,
|
||||
.setattr = kernfs_iop_setattr,
|
||||
.getattr = kernfs_iop_getattr,
|
||||
.permission = kernfs_iop_permission,
|
||||
|
25
fs/libfs.c
25
fs/libfs.c
@ -1024,15 +1024,18 @@ int noop_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
}
|
||||
EXPORT_SYMBOL(noop_fsync);
|
||||
|
||||
void kfree_put_link(struct dentry *dentry, struct nameidata *nd,
|
||||
void *cookie)
|
||||
void kfree_put_link(struct inode *unused, void *cookie)
|
||||
{
|
||||
char *s = nd_get_link(nd);
|
||||
if (!IS_ERR(s))
|
||||
kfree(s);
|
||||
kfree(cookie);
|
||||
}
|
||||
EXPORT_SYMBOL(kfree_put_link);
|
||||
|
||||
void free_page_put_link(struct inode *unused, void *cookie)
|
||||
{
|
||||
free_page((unsigned long) cookie);
|
||||
}
|
||||
EXPORT_SYMBOL(free_page_put_link);
|
||||
|
||||
/*
|
||||
* nop .set_page_dirty method so that people can use .page_mkwrite on
|
||||
* anon inodes.
|
||||
@ -1093,3 +1096,15 @@ simple_nosetlease(struct file *filp, long arg, struct file_lock **flp,
|
||||
return -EINVAL;
|
||||
}
|
||||
EXPORT_SYMBOL(simple_nosetlease);
|
||||
|
||||
const char *simple_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
return d_inode(dentry)->i_link;
|
||||
}
|
||||
EXPORT_SYMBOL(simple_follow_link);
|
||||
|
||||
const struct inode_operations simple_symlink_inode_operations = {
|
||||
.follow_link = simple_follow_link,
|
||||
.readlink = generic_readlink
|
||||
};
|
||||
EXPORT_SYMBOL(simple_symlink_inode_operations);
|
||||
|
@ -779,6 +779,7 @@ fail:
|
||||
const struct inode_operations logfs_symlink_iops = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = page_follow_link_light,
|
||||
.put_link = page_put_link,
|
||||
};
|
||||
|
||||
const struct inode_operations logfs_dir_iops = {
|
||||
|
@ -88,6 +88,7 @@ static inline int is_mounted(struct vfsmount *mnt)
|
||||
extern struct mount *__lookup_mnt(struct vfsmount *, struct dentry *);
|
||||
extern struct mount *__lookup_mnt_last(struct vfsmount *, struct dentry *);
|
||||
|
||||
extern int __legitimize_mnt(struct vfsmount *, unsigned);
|
||||
extern bool legitimize_mnt(struct vfsmount *, unsigned);
|
||||
|
||||
extern void __detach_mounts(struct dentry *dentry);
|
||||
|
1455
fs/namei.c
1455
fs/namei.c
File diff suppressed because it is too large
Load Diff
@ -590,24 +590,35 @@ static void delayed_free_vfsmnt(struct rcu_head *head)
|
||||
}
|
||||
|
||||
/* call under rcu_read_lock */
|
||||
bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
|
||||
int __legitimize_mnt(struct vfsmount *bastard, unsigned seq)
|
||||
{
|
||||
struct mount *mnt;
|
||||
if (read_seqretry(&mount_lock, seq))
|
||||
return false;
|
||||
return 1;
|
||||
if (bastard == NULL)
|
||||
return true;
|
||||
return 0;
|
||||
mnt = real_mount(bastard);
|
||||
mnt_add_count(mnt, 1);
|
||||
if (likely(!read_seqretry(&mount_lock, seq)))
|
||||
return true;
|
||||
return 0;
|
||||
if (bastard->mnt_flags & MNT_SYNC_UMOUNT) {
|
||||
mnt_add_count(mnt, -1);
|
||||
return false;
|
||||
return 1;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* call under rcu_read_lock */
|
||||
bool legitimize_mnt(struct vfsmount *bastard, unsigned seq)
|
||||
{
|
||||
int res = __legitimize_mnt(bastard, seq);
|
||||
if (likely(!res))
|
||||
return true;
|
||||
if (unlikely(res < 0)) {
|
||||
rcu_read_unlock();
|
||||
mntput(bastard);
|
||||
rcu_read_lock();
|
||||
}
|
||||
rcu_read_unlock();
|
||||
mntput(bastard);
|
||||
rcu_read_lock();
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -20,7 +20,6 @@
|
||||
#include <linux/stat.h>
|
||||
#include <linux/mm.h>
|
||||
#include <linux/string.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
/* Symlink caching in the page cache is even more simplistic
|
||||
* and straight-forward than readdir caching.
|
||||
@ -43,7 +42,7 @@ error:
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *nfs_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct page *page;
|
||||
@ -51,19 +50,13 @@ static void *nfs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
|
||||
err = ERR_PTR(nfs_revalidate_mapping(inode, inode->i_mapping));
|
||||
if (err)
|
||||
goto read_failed;
|
||||
return err;
|
||||
page = read_cache_page(&inode->i_data, 0,
|
||||
(filler_t *)nfs_symlink_filler, inode);
|
||||
if (IS_ERR(page)) {
|
||||
err = page;
|
||||
goto read_failed;
|
||||
}
|
||||
nd_set_link(nd, kmap(page));
|
||||
return page;
|
||||
|
||||
read_failed:
|
||||
nd_set_link(nd, err);
|
||||
return NULL;
|
||||
if (IS_ERR(page))
|
||||
return ERR_CAST(page);
|
||||
*cookie = page;
|
||||
return kmap(page);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -35,7 +35,7 @@
|
||||
* ntfs_lookup - find the inode represented by a dentry in a directory inode
|
||||
* @dir_ino: directory inode in which to look for the inode
|
||||
* @dent: dentry representing the inode to look for
|
||||
* @nd: lookup nameidata
|
||||
* @flags: lookup flags
|
||||
*
|
||||
* In short, ntfs_lookup() looks for the inode represented by the dentry @dent
|
||||
* in the directory inode @dir_ino and if found attaches the inode to the
|
||||
|
@ -367,7 +367,7 @@ retry:
|
||||
if (res)
|
||||
goto out;
|
||||
|
||||
inode = path.dentry->d_inode;
|
||||
inode = d_backing_inode(path.dentry);
|
||||
|
||||
if ((mode & MAY_EXEC) && S_ISREG(inode->i_mode)) {
|
||||
/*
|
||||
|
@ -140,11 +140,12 @@ struct ovl_link_data {
|
||||
void *cookie;
|
||||
};
|
||||
|
||||
static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *ovl_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
void *ret;
|
||||
struct dentry *realdentry;
|
||||
struct inode *realinode;
|
||||
struct ovl_link_data *data = NULL;
|
||||
const char *ret;
|
||||
|
||||
realdentry = ovl_dentry_real(dentry);
|
||||
realinode = realdentry->d_inode;
|
||||
@ -152,28 +153,28 @@ static void *ovl_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
if (WARN_ON(!realinode->i_op->follow_link))
|
||||
return ERR_PTR(-EPERM);
|
||||
|
||||
ret = realinode->i_op->follow_link(realdentry, nd);
|
||||
if (IS_ERR(ret))
|
||||
return ret;
|
||||
|
||||
if (realinode->i_op->put_link) {
|
||||
struct ovl_link_data *data;
|
||||
|
||||
data = kmalloc(sizeof(struct ovl_link_data), GFP_KERNEL);
|
||||
if (!data) {
|
||||
realinode->i_op->put_link(realdentry, nd, ret);
|
||||
if (!data)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
}
|
||||
data->realdentry = realdentry;
|
||||
data->cookie = ret;
|
||||
|
||||
return data;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ret = realinode->i_op->follow_link(realdentry, cookie);
|
||||
if (IS_ERR_OR_NULL(ret)) {
|
||||
kfree(data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (data)
|
||||
data->cookie = *cookie;
|
||||
|
||||
*cookie = data;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
|
||||
static void ovl_put_link(struct inode *unused, void *c)
|
||||
{
|
||||
struct inode *realinode;
|
||||
struct ovl_link_data *data = c;
|
||||
@ -182,7 +183,7 @@ static void ovl_put_link(struct dentry *dentry, struct nameidata *nd, void *c)
|
||||
return;
|
||||
|
||||
realinode = data->realdentry->d_inode;
|
||||
realinode->i_op->put_link(data->realdentry, nd, data->cookie);
|
||||
realinode->i_op->put_link(realinode, data->cookie);
|
||||
kfree(data);
|
||||
}
|
||||
|
||||
|
@ -1380,7 +1380,7 @@ static int proc_exe_link(struct dentry *dentry, struct path *exe_path)
|
||||
return -ENOENT;
|
||||
}
|
||||
|
||||
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *proc_pid_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
struct path path;
|
||||
@ -1394,7 +1394,7 @@ static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
if (error)
|
||||
goto out;
|
||||
|
||||
nd_jump_link(nd, &path);
|
||||
nd_jump_link(&path);
|
||||
return NULL;
|
||||
out:
|
||||
return ERR_PTR(error);
|
||||
|
@ -23,7 +23,6 @@
|
||||
#include <linux/slab.h>
|
||||
#include <linux/mount.h>
|
||||
#include <linux/magic.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
@ -394,16 +393,16 @@ static const struct file_operations proc_reg_file_ops_no_compat = {
|
||||
};
|
||||
#endif
|
||||
|
||||
static void *proc_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *proc_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct proc_dir_entry *pde = PDE(d_inode(dentry));
|
||||
if (unlikely(!use_pde(pde)))
|
||||
return ERR_PTR(-EINVAL);
|
||||
nd_set_link(nd, pde->data);
|
||||
return pde;
|
||||
*cookie = pde;
|
||||
return pde->data;
|
||||
}
|
||||
|
||||
static void proc_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
|
||||
static void proc_put_link(struct inode *unused, void *p)
|
||||
{
|
||||
unuse_pde(p);
|
||||
}
|
||||
|
@ -30,7 +30,7 @@ static const struct proc_ns_operations *ns_entries[] = {
|
||||
&mntns_operations,
|
||||
};
|
||||
|
||||
static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *proc_ns_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct inode *inode = d_inode(dentry);
|
||||
const struct proc_ns_operations *ns_ops = PROC_I(inode)->ns_ops;
|
||||
@ -45,7 +45,7 @@ static void *proc_ns_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
if (ptrace_may_access(task, PTRACE_MODE_READ)) {
|
||||
error = ns_get_path(&ns_path, task, ns_ops);
|
||||
if (!error)
|
||||
nd_jump_link(nd, &ns_path);
|
||||
nd_jump_link(&ns_path);
|
||||
}
|
||||
put_task_struct(task);
|
||||
return error;
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
#include "internal.h"
|
||||
@ -19,21 +18,20 @@ static int proc_self_readlink(struct dentry *dentry, char __user *buffer,
|
||||
return readlink_copy(buffer, buflen, tmp);
|
||||
}
|
||||
|
||||
static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *proc_self_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct pid_namespace *ns = dentry->d_sb->s_fs_info;
|
||||
pid_t tgid = task_tgid_nr_ns(current, ns);
|
||||
char *name = ERR_PTR(-ENOENT);
|
||||
if (tgid) {
|
||||
/* 11 for max length of signed int in decimal + NULL term */
|
||||
name = kmalloc(12, GFP_KERNEL);
|
||||
if (!name)
|
||||
name = ERR_PTR(-ENOMEM);
|
||||
else
|
||||
sprintf(name, "%d", tgid);
|
||||
}
|
||||
nd_set_link(nd, name);
|
||||
return NULL;
|
||||
char *name;
|
||||
|
||||
if (!tgid)
|
||||
return ERR_PTR(-ENOENT);
|
||||
/* 11 for max length of signed int in decimal + NULL term */
|
||||
name = kmalloc(12, GFP_KERNEL);
|
||||
if (!name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
sprintf(name, "%d", tgid);
|
||||
return *cookie = name;
|
||||
}
|
||||
|
||||
static const struct inode_operations proc_self_inode_operations = {
|
||||
|
@ -1,5 +1,4 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/slab.h>
|
||||
#include <linux/pid_namespace.h>
|
||||
#include "internal.h"
|
||||
@ -20,21 +19,20 @@ static int proc_thread_self_readlink(struct dentry *dentry, char __user *buffer,
|
||||
return readlink_copy(buffer, buflen, tmp);
|
||||
}
|
||||
|
||||
static void *proc_thread_self_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *proc_thread_self_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct pid_namespace *ns = dentry->d_sb->s_fs_info;
|
||||
pid_t tgid = task_tgid_nr_ns(current, ns);
|
||||
pid_t pid = task_pid_nr_ns(current, ns);
|
||||
char *name = ERR_PTR(-ENOENT);
|
||||
if (pid) {
|
||||
name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
|
||||
if (!name)
|
||||
name = ERR_PTR(-ENOMEM);
|
||||
else
|
||||
sprintf(name, "%d/task/%d", tgid, pid);
|
||||
}
|
||||
nd_set_link(nd, name);
|
||||
return NULL;
|
||||
char *name;
|
||||
|
||||
if (!pid)
|
||||
return ERR_PTR(-ENOENT);
|
||||
name = kmalloc(PROC_NUMBUF + 6 + PROC_NUMBUF, GFP_KERNEL);
|
||||
if (!name)
|
||||
return ERR_PTR(-ENOMEM);
|
||||
sprintf(name, "%d/task/%d", tgid, pid);
|
||||
return *cookie = name;
|
||||
}
|
||||
|
||||
static const struct inode_operations proc_thread_self_inode_operations = {
|
||||
|
@ -5,4 +5,4 @@
|
||||
obj-$(CONFIG_SYSV_FS) += sysv.o
|
||||
|
||||
sysv-objs := ialloc.o balloc.o inode.o itree.o file.o dir.o \
|
||||
namei.o super.o symlink.o
|
||||
namei.o super.o
|
||||
|
@ -166,8 +166,9 @@ void sysv_set_inode(struct inode *inode, dev_t rdev)
|
||||
inode->i_op = &sysv_symlink_inode_operations;
|
||||
inode->i_mapping->a_ops = &sysv_aops;
|
||||
} else {
|
||||
inode->i_op = &sysv_fast_symlink_inode_operations;
|
||||
nd_terminate_link(SYSV_I(inode)->i_data, inode->i_size,
|
||||
inode->i_op = &simple_symlink_inode_operations;
|
||||
inode->i_link = (char *)SYSV_I(inode)->i_data;
|
||||
nd_terminate_link(inode->i_link, inode->i_size,
|
||||
sizeof(SYSV_I(inode)->i_data) - 1);
|
||||
}
|
||||
} else
|
||||
|
@ -1,20 +0,0 @@
|
||||
/*
|
||||
* linux/fs/sysv/symlink.c
|
||||
*
|
||||
* Handling of System V filesystem fast symlinks extensions.
|
||||
* Aug 2001, Christoph Hellwig (hch@infradead.org)
|
||||
*/
|
||||
|
||||
#include "sysv.h"
|
||||
#include <linux/namei.h>
|
||||
|
||||
static void *sysv_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
nd_set_link(nd, (char *)SYSV_I(d_inode(dentry))->i_data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations sysv_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = sysv_follow_link,
|
||||
};
|
@ -161,7 +161,6 @@ extern ino_t sysv_inode_by_name(struct dentry *);
|
||||
|
||||
extern const struct inode_operations sysv_file_inode_operations;
|
||||
extern const struct inode_operations sysv_dir_inode_operations;
|
||||
extern const struct inode_operations sysv_fast_symlink_inode_operations;
|
||||
extern const struct file_operations sysv_file_operations;
|
||||
extern const struct file_operations sysv_dir_operations;
|
||||
extern const struct address_space_operations sysv_aops;
|
||||
|
@ -889,6 +889,7 @@ static int ubifs_symlink(struct inode *dir, struct dentry *dentry,
|
||||
|
||||
memcpy(ui->data, symname, len);
|
||||
((char *)ui->data)[len] = '\0';
|
||||
inode->i_link = ui->data;
|
||||
/*
|
||||
* The terminating zero byte is not written to the flash media and it
|
||||
* is put just to make later in-memory string processing simpler. Thus,
|
||||
|
@ -51,7 +51,6 @@
|
||||
|
||||
#include "ubifs.h"
|
||||
#include <linux/mount.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/slab.h>
|
||||
|
||||
static int read_block(struct inode *inode, void *addr, unsigned int block,
|
||||
@ -1300,14 +1299,6 @@ static void ubifs_invalidatepage(struct page *page, unsigned int offset,
|
||||
ClearPageChecked(page);
|
||||
}
|
||||
|
||||
static void *ubifs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ubifs_inode *ui = ubifs_inode(d_inode(dentry));
|
||||
|
||||
nd_set_link(nd, ui->data);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int ubifs_fsync(struct file *file, loff_t start, loff_t end, int datasync)
|
||||
{
|
||||
struct inode *inode = file->f_mapping->host;
|
||||
@ -1570,7 +1561,7 @@ const struct inode_operations ubifs_file_inode_operations = {
|
||||
|
||||
const struct inode_operations ubifs_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ubifs_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = ubifs_setattr,
|
||||
.getattr = ubifs_getattr,
|
||||
.setxattr = ubifs_setxattr,
|
||||
|
@ -195,6 +195,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum)
|
||||
}
|
||||
memcpy(ui->data, ino->data, ui->data_len);
|
||||
((char *)ui->data)[ui->data_len] = '\0';
|
||||
inode->i_link = ui->data;
|
||||
break;
|
||||
case S_IFBLK:
|
||||
case S_IFCHR:
|
||||
|
@ -572,9 +572,10 @@ static void ufs_set_inode_ops(struct inode *inode)
|
||||
inode->i_fop = &ufs_dir_operations;
|
||||
inode->i_mapping->a_ops = &ufs_aops;
|
||||
} else if (S_ISLNK(inode->i_mode)) {
|
||||
if (!inode->i_blocks)
|
||||
if (!inode->i_blocks) {
|
||||
inode->i_op = &ufs_fast_symlink_inode_operations;
|
||||
else {
|
||||
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
|
||||
} else {
|
||||
inode->i_op = &ufs_symlink_inode_operations;
|
||||
inode->i_mapping->a_ops = &ufs_aops;
|
||||
}
|
||||
|
@ -144,7 +144,8 @@ static int ufs_symlink (struct inode * dir, struct dentry * dentry,
|
||||
} else {
|
||||
/* fast symlink */
|
||||
inode->i_op = &ufs_fast_symlink_inode_operations;
|
||||
memcpy(UFS_I(inode)->i_u1.i_symlink, symname, l);
|
||||
inode->i_link = (char *)UFS_I(inode)->i_u1.i_symlink;
|
||||
memcpy(inode->i_link, symname, l);
|
||||
inode->i_size = l-1;
|
||||
}
|
||||
mark_inode_dirty(inode);
|
||||
|
@ -25,23 +25,12 @@
|
||||
* ext2 symlink handling code
|
||||
*/
|
||||
|
||||
#include <linux/fs.h>
|
||||
#include <linux/namei.h>
|
||||
|
||||
#include "ufs_fs.h"
|
||||
#include "ufs.h"
|
||||
|
||||
|
||||
static void *ufs_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
struct ufs_inode_info *p = UFS_I(d_inode(dentry));
|
||||
nd_set_link(nd, (char*)p->i_u1.i_symlink);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const struct inode_operations ufs_fast_symlink_inode_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = ufs_follow_link,
|
||||
.follow_link = simple_follow_link,
|
||||
.setattr = ufs_setattr,
|
||||
};
|
||||
|
||||
|
@ -41,7 +41,6 @@
|
||||
|
||||
#include <linux/capability.h>
|
||||
#include <linux/xattr.h>
|
||||
#include <linux/namei.h>
|
||||
#include <linux/posix_acl.h>
|
||||
#include <linux/security.h>
|
||||
#include <linux/fiemap.h>
|
||||
@ -414,10 +413,10 @@ xfs_vn_rename(
|
||||
* we need to be very careful about how much stack we use.
|
||||
* uio is kmalloced for this reason...
|
||||
*/
|
||||
STATIC void *
|
||||
STATIC const char *
|
||||
xfs_vn_follow_link(
|
||||
struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
void **cookie)
|
||||
{
|
||||
char *link;
|
||||
int error = -ENOMEM;
|
||||
@ -430,14 +429,12 @@ xfs_vn_follow_link(
|
||||
if (unlikely(error))
|
||||
goto out_kfree;
|
||||
|
||||
nd_set_link(nd, link);
|
||||
return NULL;
|
||||
return *cookie = link;
|
||||
|
||||
out_kfree:
|
||||
kfree(link);
|
||||
out_err:
|
||||
nd_set_link(nd, ERR_PTR(error));
|
||||
return NULL;
|
||||
return ERR_PTR(error);
|
||||
}
|
||||
|
||||
STATIC int
|
||||
|
@ -45,7 +45,6 @@ extern struct dentry *arch_debugfs_dir;
|
||||
|
||||
/* declared over in file.c */
|
||||
extern const struct file_operations debugfs_file_operations;
|
||||
extern const struct inode_operations debugfs_link_operations;
|
||||
|
||||
struct dentry *debugfs_create_file(const char *name, umode_t mode,
|
||||
struct dentry *parent, void *data,
|
||||
|
@ -38,7 +38,6 @@ struct backing_dev_info;
|
||||
struct export_operations;
|
||||
struct hd_geometry;
|
||||
struct iovec;
|
||||
struct nameidata;
|
||||
struct kiocb;
|
||||
struct kobject;
|
||||
struct pipe_inode_info;
|
||||
@ -656,6 +655,7 @@ struct inode {
|
||||
struct pipe_inode_info *i_pipe;
|
||||
struct block_device *i_bdev;
|
||||
struct cdev *i_cdev;
|
||||
char *i_link;
|
||||
};
|
||||
|
||||
__u32 i_generation;
|
||||
@ -1607,12 +1607,12 @@ struct file_operations {
|
||||
|
||||
struct inode_operations {
|
||||
struct dentry * (*lookup) (struct inode *,struct dentry *, unsigned int);
|
||||
void * (*follow_link) (struct dentry *, struct nameidata *);
|
||||
const char * (*follow_link) (struct dentry *, void **);
|
||||
int (*permission) (struct inode *, int);
|
||||
struct posix_acl * (*get_acl)(struct inode *, int);
|
||||
|
||||
int (*readlink) (struct dentry *, char __user *,int);
|
||||
void (*put_link) (struct dentry *, struct nameidata *, void *);
|
||||
void (*put_link) (struct inode *, void *);
|
||||
|
||||
int (*create) (struct inode *,struct dentry *, umode_t, bool);
|
||||
int (*link) (struct dentry *,struct inode *,struct dentry *);
|
||||
@ -1879,6 +1879,7 @@ enum file_time_flags {
|
||||
S_VERSION = 8,
|
||||
};
|
||||
|
||||
extern bool atime_needs_update(const struct path *, struct inode *);
|
||||
extern void touch_atime(const struct path *);
|
||||
static inline void file_accessed(struct file *file)
|
||||
{
|
||||
@ -2704,13 +2705,14 @@ extern const struct file_operations generic_ro_fops;
|
||||
|
||||
extern int readlink_copy(char __user *, int, const char *);
|
||||
extern int page_readlink(struct dentry *, char __user *, int);
|
||||
extern void *page_follow_link_light(struct dentry *, struct nameidata *);
|
||||
extern void page_put_link(struct dentry *, struct nameidata *, void *);
|
||||
extern const char *page_follow_link_light(struct dentry *, void **);
|
||||
extern void page_put_link(struct inode *, void *);
|
||||
extern int __page_symlink(struct inode *inode, const char *symname, int len,
|
||||
int nofs);
|
||||
extern int page_symlink(struct inode *inode, const char *symname, int len);
|
||||
extern const struct inode_operations page_symlink_inode_operations;
|
||||
extern void kfree_put_link(struct dentry *, struct nameidata *, void *);
|
||||
extern void kfree_put_link(struct inode *, void *);
|
||||
extern void free_page_put_link(struct inode *, void *);
|
||||
extern int generic_readlink(struct dentry *, char __user *, int);
|
||||
extern void generic_fillattr(struct inode *, struct kstat *);
|
||||
int vfs_getattr_nosec(struct path *path, struct kstat *stat);
|
||||
@ -2721,6 +2723,8 @@ void __inode_sub_bytes(struct inode *inode, loff_t bytes);
|
||||
void inode_sub_bytes(struct inode *inode, loff_t bytes);
|
||||
loff_t inode_get_bytes(struct inode *inode);
|
||||
void inode_set_bytes(struct inode *inode, loff_t bytes);
|
||||
const char *simple_follow_link(struct dentry *, void **);
|
||||
extern const struct inode_operations simple_symlink_inode_operations;
|
||||
|
||||
extern int iterate_dir(struct file *, struct dir_context *);
|
||||
|
||||
|
@ -1,16 +1,15 @@
|
||||
#ifndef _LINUX_NAMEI_H
|
||||
#define _LINUX_NAMEI_H
|
||||
|
||||
#include <linux/dcache.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/linkage.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/path.h>
|
||||
|
||||
struct vfsmount;
|
||||
struct nameidata;
|
||||
#include <linux/fcntl.h>
|
||||
#include <linux/errno.h>
|
||||
|
||||
enum { MAX_NESTED_LINKS = 8 };
|
||||
|
||||
#define MAXSYMLINKS 40
|
||||
|
||||
/*
|
||||
* Type of the last component on LOOKUP_PARENT
|
||||
*/
|
||||
@ -45,13 +44,29 @@ enum {LAST_NORM, LAST_ROOT, LAST_DOT, LAST_DOTDOT, LAST_BIND};
|
||||
#define LOOKUP_ROOT 0x2000
|
||||
#define LOOKUP_EMPTY 0x4000
|
||||
|
||||
extern int user_path_at(int, const char __user *, unsigned, struct path *);
|
||||
extern int user_path_at_empty(int, const char __user *, unsigned, struct path *, int *empty);
|
||||
|
||||
#define user_path(name, path) user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW, path)
|
||||
#define user_lpath(name, path) user_path_at(AT_FDCWD, name, 0, path)
|
||||
#define user_path_dir(name, path) \
|
||||
user_path_at(AT_FDCWD, name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path)
|
||||
static inline int user_path_at(int dfd, const char __user *name, unsigned flags,
|
||||
struct path *path)
|
||||
{
|
||||
return user_path_at_empty(dfd, name, flags, path, NULL);
|
||||
}
|
||||
|
||||
static inline int user_path(const char __user *name, struct path *path)
|
||||
{
|
||||
return user_path_at_empty(AT_FDCWD, name, LOOKUP_FOLLOW, path, NULL);
|
||||
}
|
||||
|
||||
static inline int user_lpath(const char __user *name, struct path *path)
|
||||
{
|
||||
return user_path_at_empty(AT_FDCWD, name, 0, path, NULL);
|
||||
}
|
||||
|
||||
static inline int user_path_dir(const char __user *name, struct path *path)
|
||||
{
|
||||
return user_path_at_empty(AT_FDCWD, name,
|
||||
LOOKUP_FOLLOW | LOOKUP_DIRECTORY, path, NULL);
|
||||
}
|
||||
|
||||
extern int kern_path(const char *, unsigned, struct path *);
|
||||
|
||||
@ -70,9 +85,7 @@ extern int follow_up(struct path *);
|
||||
extern struct dentry *lock_rename(struct dentry *, struct dentry *);
|
||||
extern void unlock_rename(struct dentry *, struct dentry *);
|
||||
|
||||
extern void nd_jump_link(struct nameidata *nd, struct path *path);
|
||||
extern void nd_set_link(struct nameidata *nd, char *path);
|
||||
extern char *nd_get_link(struct nameidata *nd);
|
||||
extern void nd_jump_link(struct path *path);
|
||||
|
||||
static inline void nd_terminate_link(void *name, size_t len, size_t maxlen)
|
||||
{
|
||||
|
@ -132,6 +132,7 @@ struct fs_struct;
|
||||
struct perf_event_context;
|
||||
struct blk_plug;
|
||||
struct filename;
|
||||
struct nameidata;
|
||||
|
||||
#define VMACACHE_BITS 2
|
||||
#define VMACACHE_SIZE (1U << VMACACHE_BITS)
|
||||
@ -1461,7 +1462,7 @@ struct task_struct {
|
||||
it with task_lock())
|
||||
- initialized normally by setup_new_exec */
|
||||
/* file system info */
|
||||
int link_count, total_link_count;
|
||||
struct nameidata *nameidata;
|
||||
#ifdef CONFIG_SYSVIPC
|
||||
/* ipc stuff */
|
||||
struct sysv_sem sysvsem;
|
||||
|
@ -43,7 +43,6 @@ struct file;
|
||||
struct vfsmount;
|
||||
struct path;
|
||||
struct qstr;
|
||||
struct nameidata;
|
||||
struct iattr;
|
||||
struct fown_struct;
|
||||
struct file_operations;
|
||||
@ -477,7 +476,8 @@ static inline void security_free_mnt_opts(struct security_mnt_opts *opts)
|
||||
* @inode_follow_link:
|
||||
* Check permission to follow a symbolic link when looking up a pathname.
|
||||
* @dentry contains the dentry structure for the link.
|
||||
* @nd contains the nameidata structure for the parent directory.
|
||||
* @inode contains the inode, which itself is not stable in RCU-walk
|
||||
* @rcu indicates whether we are in RCU-walk mode.
|
||||
* Return 0 if permission is granted.
|
||||
* @inode_permission:
|
||||
* Check permission before accessing an inode. This hook is called by the
|
||||
@ -1553,7 +1553,8 @@ struct security_operations {
|
||||
int (*inode_rename) (struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry);
|
||||
int (*inode_readlink) (struct dentry *dentry);
|
||||
int (*inode_follow_link) (struct dentry *dentry, struct nameidata *nd);
|
||||
int (*inode_follow_link) (struct dentry *dentry, struct inode *inode,
|
||||
bool rcu);
|
||||
int (*inode_permission) (struct inode *inode, int mask);
|
||||
int (*inode_setattr) (struct dentry *dentry, struct iattr *attr);
|
||||
int (*inode_getattr) (const struct path *path);
|
||||
@ -1839,7 +1840,8 @@ int security_inode_rename(struct inode *old_dir, struct dentry *old_dentry,
|
||||
struct inode *new_dir, struct dentry *new_dentry,
|
||||
unsigned int flags);
|
||||
int security_inode_readlink(struct dentry *dentry);
|
||||
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd);
|
||||
int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
|
||||
bool rcu);
|
||||
int security_inode_permission(struct inode *inode, int mask);
|
||||
int security_inode_setattr(struct dentry *dentry, struct iattr *attr);
|
||||
int security_inode_getattr(const struct path *path);
|
||||
@ -2242,7 +2244,8 @@ static inline int security_inode_readlink(struct dentry *dentry)
|
||||
}
|
||||
|
||||
static inline int security_inode_follow_link(struct dentry *dentry,
|
||||
struct nameidata *nd)
|
||||
struct inode *inode,
|
||||
bool rcu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
32
mm/shmem.c
32
mm/shmem.c
@ -2451,6 +2451,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
|
||||
return -ENOMEM;
|
||||
}
|
||||
inode->i_op = &shmem_short_symlink_operations;
|
||||
inode->i_link = info->symlink;
|
||||
} else {
|
||||
error = shmem_getpage(inode, 0, &page, SGP_WRITE, NULL);
|
||||
if (error) {
|
||||
@ -2474,30 +2475,23 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void *shmem_follow_short_symlink(struct dentry *dentry, struct nameidata *nd)
|
||||
{
|
||||
nd_set_link(nd, SHMEM_I(d_inode(dentry))->symlink);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *shmem_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
static const char *shmem_follow_link(struct dentry *dentry, void **cookie)
|
||||
{
|
||||
struct page *page = NULL;
|
||||
int error = shmem_getpage(d_inode(dentry), 0, &page, SGP_READ, NULL);
|
||||
nd_set_link(nd, error ? ERR_PTR(error) : kmap(page));
|
||||
if (page)
|
||||
unlock_page(page);
|
||||
return page;
|
||||
if (error)
|
||||
return ERR_PTR(error);
|
||||
unlock_page(page);
|
||||
*cookie = page;
|
||||
return kmap(page);
|
||||
}
|
||||
|
||||
static void shmem_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie)
|
||||
static void shmem_put_link(struct inode *unused, void *cookie)
|
||||
{
|
||||
if (!IS_ERR(nd_get_link(nd))) {
|
||||
struct page *page = cookie;
|
||||
kunmap(page);
|
||||
mark_page_accessed(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
struct page *page = cookie;
|
||||
kunmap(page);
|
||||
mark_page_accessed(page);
|
||||
page_cache_release(page);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_TMPFS_XATTR
|
||||
@ -2642,7 +2636,7 @@ static ssize_t shmem_listxattr(struct dentry *dentry, char *buffer, size_t size)
|
||||
|
||||
static const struct inode_operations shmem_short_symlink_operations = {
|
||||
.readlink = generic_readlink,
|
||||
.follow_link = shmem_follow_short_symlink,
|
||||
.follow_link = simple_follow_link,
|
||||
#ifdef CONFIG_TMPFS_XATTR
|
||||
.setxattr = shmem_setxattr,
|
||||
.getxattr = shmem_getxattr,
|
||||
|
@ -209,8 +209,8 @@ static int cap_inode_readlink(struct dentry *dentry)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int cap_inode_follow_link(struct dentry *dentry,
|
||||
struct nameidata *nameidata)
|
||||
static int cap_inode_follow_link(struct dentry *dentry, struct inode *inode,
|
||||
bool rcu)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -581,11 +581,12 @@ int security_inode_readlink(struct dentry *dentry)
|
||||
return security_ops->inode_readlink(dentry);
|
||||
}
|
||||
|
||||
int security_inode_follow_link(struct dentry *dentry, struct nameidata *nd)
|
||||
int security_inode_follow_link(struct dentry *dentry, struct inode *inode,
|
||||
bool rcu)
|
||||
{
|
||||
if (unlikely(IS_PRIVATE(d_backing_inode(dentry))))
|
||||
if (unlikely(IS_PRIVATE(inode)))
|
||||
return 0;
|
||||
return security_ops->inode_follow_link(dentry, nd);
|
||||
return security_ops->inode_follow_link(dentry, inode, rcu);
|
||||
}
|
||||
|
||||
int security_inode_permission(struct inode *inode, int mask)
|
||||
|
@ -761,7 +761,23 @@ int avc_has_perm(u32 ssid, u32 tsid, u16 tclass,
|
||||
|
||||
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
|
||||
|
||||
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata);
|
||||
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc, auditdata, 0);
|
||||
if (rc2)
|
||||
return rc2;
|
||||
return rc;
|
||||
}
|
||||
|
||||
int avc_has_perm_flags(u32 ssid, u32 tsid, u16 tclass,
|
||||
u32 requested, struct common_audit_data *auditdata,
|
||||
int flags)
|
||||
{
|
||||
struct av_decision avd;
|
||||
int rc, rc2;
|
||||
|
||||
rc = avc_has_perm_noaudit(ssid, tsid, tclass, requested, 0, &avd);
|
||||
|
||||
rc2 = avc_audit(ssid, tsid, tclass, requested, &avd, rc,
|
||||
auditdata, flags);
|
||||
if (rc2)
|
||||
return rc2;
|
||||
return rc;
|
||||
|
@ -1564,7 +1564,7 @@ static int cred_has_capability(const struct cred *cred,
|
||||
|
||||
rc = avc_has_perm_noaudit(sid, sid, sclass, av, 0, &avd);
|
||||
if (audit == SECURITY_CAP_AUDIT) {
|
||||
int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad);
|
||||
int rc2 = avc_audit(sid, sid, sclass, av, &avd, rc, &ad, 0);
|
||||
if (rc2)
|
||||
return rc2;
|
||||
}
|
||||
@ -2861,11 +2861,23 @@ static int selinux_inode_readlink(struct dentry *dentry)
|
||||
return dentry_has_perm(cred, dentry, FILE__READ);
|
||||
}
|
||||
|
||||
static int selinux_inode_follow_link(struct dentry *dentry, struct nameidata *nameidata)
|
||||
static int selinux_inode_follow_link(struct dentry *dentry, struct inode *inode,
|
||||
bool rcu)
|
||||
{
|
||||
const struct cred *cred = current_cred();
|
||||
struct common_audit_data ad;
|
||||
struct inode_security_struct *isec;
|
||||
u32 sid;
|
||||
|
||||
return dentry_has_perm(cred, dentry, FILE__READ);
|
||||
validate_creds(cred);
|
||||
|
||||
ad.type = LSM_AUDIT_DATA_DENTRY;
|
||||
ad.u.dentry = dentry;
|
||||
sid = cred_sid(cred);
|
||||
isec = inode->i_security;
|
||||
|
||||
return avc_has_perm_flags(sid, isec->sid, isec->sclass, FILE__READ, &ad,
|
||||
rcu ? MAY_NOT_BLOCK : 0);
|
||||
}
|
||||
|
||||
static noinline int audit_inode_permission(struct inode *inode,
|
||||
|
@ -130,7 +130,8 @@ static inline int avc_audit(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 requested,
|
||||
struct av_decision *avd,
|
||||
int result,
|
||||
struct common_audit_data *a)
|
||||
struct common_audit_data *a,
|
||||
int flags)
|
||||
{
|
||||
u32 audited, denied;
|
||||
audited = avc_audit_required(requested, avd, result, 0, &denied);
|
||||
@ -138,7 +139,7 @@ static inline int avc_audit(u32 ssid, u32 tsid,
|
||||
return 0;
|
||||
return slow_avc_audit(ssid, tsid, tclass,
|
||||
requested, audited, denied, result,
|
||||
a, 0);
|
||||
a, flags);
|
||||
}
|
||||
|
||||
#define AVC_STRICT 1 /* Ignore permissive mode. */
|
||||
@ -150,6 +151,10 @@ int avc_has_perm_noaudit(u32 ssid, u32 tsid,
|
||||
int avc_has_perm(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 requested,
|
||||
struct common_audit_data *auditdata);
|
||||
int avc_has_perm_flags(u32 ssid, u32 tsid,
|
||||
u16 tclass, u32 requested,
|
||||
struct common_audit_data *auditdata,
|
||||
int flags);
|
||||
|
||||
u32 avc_policy_seqno(void);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user