static int unionfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz) { int err; struct dentry *parent; unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD); parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT); unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD); if (unlikely(!__unionfs_d_revalidate(dentry, parent, false, 0))) { err = -ESTALE; goto out; } err = __unionfs_readlink(dentry, buf, bufsiz); out: unionfs_check_dentry(dentry); unionfs_unlock_dentry(dentry); unionfs_unlock_parent(dentry, parent); unionfs_read_unlock(dentry->d_sb); return err; }
static void *unionfs_follow_link(struct dentry *dentry, struct nameidata *nd) { char *buf; int len = PAGE_SIZE, err; mm_segment_t old_fs; struct dentry *parent; unionfs_read_lock(dentry->d_sb, UNIONFS_SMUTEX_CHILD); parent = unionfs_lock_parent(dentry, UNIONFS_DMUTEX_PARENT); unionfs_lock_dentry(dentry, UNIONFS_DMUTEX_CHILD); /* This is freed by the put_link method assuming a successful call. */ buf = kmalloc(len, GFP_KERNEL); if (unlikely(!buf)) { err = -ENOMEM; goto out; } /* read the symlink, and then we will follow it */ old_fs = get_fs(); set_fs(KERNEL_DS); err = __unionfs_readlink(dentry, buf, len); set_fs(old_fs); if (err < 0) { kfree(buf); buf = NULL; goto out; } buf[err] = 0; nd_set_link(nd, buf); err = 0; out: if (err >= 0) { unionfs_check_nd(nd); unionfs_check_dentry(dentry); } unionfs_unlock_dentry(dentry); unionfs_unlock_parent(dentry, parent); unionfs_read_unlock(dentry->d_sb); return ERR_PTR(err); }