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

* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/viro/vfs-2.6: (52 commits)
  init: Open /dev/console from rootfs
  mqueue: fix typo "failues" -> "failures"
  mqueue: only set error codes if they are really necessary
  mqueue: simplify do_open() error handling
  mqueue: apply mathematics distributivity on mq_bytes calculation
  mqueue: remove unneeded info->messages initialization
  mqueue: fix mq_open() file descriptor leak on user-space processes
  fix race in d_splice_alias()
  set S_DEAD on unlink() and non-directory rename() victims
  vfs: add NOFOLLOW flag to umount(2)
  get rid of ->mnt_parent in tomoyo/realpath
  hppfs can use existing proc_mnt, no need for do_kern_mount() in there
  Mirror MS_KERNMOUNT in ->mnt_flags
  get rid of useless vfsmount_lock use in put_mnt_ns()
  Take vfsmount_lock to fs/internal.h
  get rid of insanity with namespace roots in tomoyo
  take check for new events in namespace (guts of mounts_poll()) to namespace.c
  Don't mess with generic_permission() under ->d_lock in hpfs
  sanitize const/signedness for udf
  nilfs: sanitize const/signedness in dealing with ->d_name.name
  ...

Fix up fairly trivial (famous last words...) conflicts in
drivers/infiniband/core/uverbs_main.c and security/tomoyo/realpath.c
This commit is contained in:
Linus Torvalds 2010-03-04 08:15:33 -08:00
commit 0f2cc4ecd8
73 changed files with 794 additions and 1101 deletions

View file

@ -837,6 +837,9 @@ replicas continue to be exactly same.
individual lists does not affect propagation or the way propagation individual lists does not affect propagation or the way propagation
tree is modified by operations. tree is modified by operations.
All vfsmounts in a peer group have the same ->mnt_master. If it is
non-NULL, they form a contiguous (ordered) segment of slave list.
A example propagation tree looks as shown in the figure below. A example propagation tree looks as shown in the figure below.
[ NOTE: Though it looks like a forest, if we consider all the shared [ NOTE: Though it looks like a forest, if we consider all the shared
mounts as a conceptual entity called 'pnode', it becomes a tree] mounts as a conceptual entity called 'pnode', it becomes a tree]
@ -874,8 +877,19 @@ replicas continue to be exactly same.
NOTE: The propagation tree is orthogonal to the mount tree. NOTE: The propagation tree is orthogonal to the mount tree.
8B Locking:
8B Algorithm: ->mnt_share, ->mnt_slave, ->mnt_slave_list, ->mnt_master are protected
by namespace_sem (exclusive for modifications, shared for reading).
Normally we have ->mnt_flags modifications serialized by vfsmount_lock.
There are two exceptions: do_add_mount() and clone_mnt().
The former modifies a vfsmount that has not been visible in any shared
data structures yet.
The latter holds namespace_sem and the only references to vfsmount
are in lists that can't be traversed without namespace_sem.
8C Algorithm:
The crux of the implementation resides in rbind/move operation. The crux of the implementation resides in rbind/move operation.

View file

@ -288,46 +288,30 @@ static int hypfs_fill_super(struct super_block *sb, void *data, int silent)
sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
sb->s_magic = HYPFS_MAGIC; sb->s_magic = HYPFS_MAGIC;
sb->s_op = &hypfs_s_ops; sb->s_op = &hypfs_s_ops;
if (hypfs_parse_options(data, sb)) { if (hypfs_parse_options(data, sb))
rc = -EINVAL; return -EINVAL;
goto err_alloc;
}
root_inode = hypfs_make_inode(sb, S_IFDIR | 0755); root_inode = hypfs_make_inode(sb, S_IFDIR | 0755);
if (!root_inode) { if (!root_inode)
rc = -ENOMEM; return -ENOMEM;
goto err_alloc;
}
root_inode->i_op = &simple_dir_inode_operations; root_inode->i_op = &simple_dir_inode_operations;
root_inode->i_fop = &simple_dir_operations; root_inode->i_fop = &simple_dir_operations;
root_dentry = d_alloc_root(root_inode); sb->s_root = root_dentry = d_alloc_root(root_inode);
if (!root_dentry) { if (!root_dentry) {
iput(root_inode); iput(root_inode);
rc = -ENOMEM; return -ENOMEM;
goto err_alloc;
} }
if (MACHINE_IS_VM) if (MACHINE_IS_VM)
rc = hypfs_vm_create_files(sb, root_dentry); rc = hypfs_vm_create_files(sb, root_dentry);
else else
rc = hypfs_diag_create_files(sb, root_dentry); rc = hypfs_diag_create_files(sb, root_dentry);
if (rc) if (rc)
goto err_tree; return rc;
sbi->update_file = hypfs_create_update_file(sb, root_dentry); sbi->update_file = hypfs_create_update_file(sb, root_dentry);
if (IS_ERR(sbi->update_file)) { if (IS_ERR(sbi->update_file))
rc = PTR_ERR(sbi->update_file); return PTR_ERR(sbi->update_file);
goto err_tree;
}
hypfs_update_update(sb); hypfs_update_update(sb);
sb->s_root = root_dentry;
pr_info("Hypervisor filesystem mounted\n"); pr_info("Hypervisor filesystem mounted\n");
return 0; return 0;
err_tree:
hypfs_delete_tree(root_dentry);
d_genocide(root_dentry);
dput(root_dentry);
err_alloc:
kfree(sbi);
return rc;
} }
static int hypfs_get_super(struct file_system_type *fst, int flags, static int hypfs_get_super(struct file_system_type *fst, int flags,
@ -340,12 +324,12 @@ static void hypfs_kill_super(struct super_block *sb)
{ {
struct hypfs_sb_info *sb_info = sb->s_fs_info; struct hypfs_sb_info *sb_info = sb->s_fs_info;
if (sb->s_root) { if (sb->s_root)
hypfs_delete_tree(sb->s_root); hypfs_delete_tree(sb->s_root);
if (sb_info->update_file)
hypfs_remove(sb_info->update_file); hypfs_remove(sb_info->update_file);
kfree(sb->s_fs_info); kfree(sb->s_fs_info);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
}
kill_litter_super(sb); kill_litter_super(sb);
} }

View file

@ -140,7 +140,7 @@ void mconsole_proc(struct mc_request *req)
goto out; goto out;
} }
err = may_open(&nd.path, MAY_READ, FMODE_READ); err = may_open(&nd.path, MAY_READ, O_RDONLY);
if (result) { if (result) {
mconsole_reply(req, "Failed to open file", 1, 0); mconsole_reply(req, "Failed to open file", 1, 0);
path_put(&nd.path); path_put(&nd.path);

View file

@ -146,7 +146,7 @@ extern struct idr ib_uverbs_srq_idr;
void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj); void idr_remove_uobj(struct idr *idp, struct ib_uobject *uobj);
struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd); int is_async);
struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd); struct ib_uverbs_event_file *ib_uverbs_lookup_comp_file(int fd);
void ib_uverbs_release_ucq(struct ib_uverbs_file *file, void ib_uverbs_release_ucq(struct ib_uverbs_file *file,

View file

@ -301,10 +301,15 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
resp.num_comp_vectors = file->device->num_comp_vectors; resp.num_comp_vectors = file->device->num_comp_vectors;
filp = ib_uverbs_alloc_event_file(file, 1, &resp.async_fd); ret = get_unused_fd();
if (ret < 0)
goto err_free;
resp.async_fd = ret;
filp = ib_uverbs_alloc_event_file(file, 1);
if (IS_ERR(filp)) { if (IS_ERR(filp)) {
ret = PTR_ERR(filp); ret = PTR_ERR(filp);
goto err_free; goto err_fd;
} }
if (copy_to_user((void __user *) (unsigned long) cmd.response, if (copy_to_user((void __user *) (unsigned long) cmd.response,
@ -332,9 +337,11 @@ ssize_t ib_uverbs_get_context(struct ib_uverbs_file *file,
return in_len; return in_len;
err_file: err_file:
put_unused_fd(resp.async_fd);
fput(filp); fput(filp);
err_fd:
put_unused_fd(resp.async_fd);
err_free: err_free:
ibdev->dealloc_ucontext(ucontext); ibdev->dealloc_ucontext(ucontext);
@ -715,6 +722,7 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
struct ib_uverbs_create_comp_channel cmd; struct ib_uverbs_create_comp_channel cmd;
struct ib_uverbs_create_comp_channel_resp resp; struct ib_uverbs_create_comp_channel_resp resp;
struct file *filp; struct file *filp;
int ret;
if (out_len < sizeof resp) if (out_len < sizeof resp)
return -ENOSPC; return -ENOSPC;
@ -722,9 +730,16 @@ ssize_t ib_uverbs_create_comp_channel(struct ib_uverbs_file *file,
if (copy_from_user(&cmd, buf, sizeof cmd)) if (copy_from_user(&cmd, buf, sizeof cmd))
return -EFAULT; return -EFAULT;
filp = ib_uverbs_alloc_event_file(file, 0, &resp.fd); ret = get_unused_fd();
if (IS_ERR(filp)) if (ret < 0)
return ret;
resp.fd = ret;
filp = ib_uverbs_alloc_event_file(file, 0);
if (IS_ERR(filp)) {
put_unused_fd(resp.fd);
return PTR_ERR(filp); return PTR_ERR(filp);
}
if (copy_to_user((void __user *) (unsigned long) cmd.response, if (copy_to_user((void __user *) (unsigned long) cmd.response,
&resp, sizeof resp)) { &resp, sizeof resp)) {

View file

@ -484,11 +484,10 @@ void ib_uverbs_event_handler(struct ib_event_handler *handler,
} }
struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file, struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
int is_async, int *fd) int is_async)
{ {
struct ib_uverbs_event_file *ev_file; struct ib_uverbs_event_file *ev_file;
struct file *filp; struct file *filp;
int ret;
ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL); ev_file = kmalloc(sizeof *ev_file, GFP_KERNEL);
if (!ev_file) if (!ev_file)
@ -503,27 +502,12 @@ struct file *ib_uverbs_alloc_event_file(struct ib_uverbs_file *uverbs_file,
ev_file->is_async = is_async; ev_file->is_async = is_async;
ev_file->is_closed = 0; ev_file->is_closed = 0;
*fd = get_unused_fd(); filp = anon_inode_getfile("[infinibandevent]", &uverbs_event_fops,
if (*fd < 0) {
ret = *fd;
goto err;
}
filp = anon_inode_getfile("[uverbs-event]", &uverbs_event_fops,
ev_file, O_RDONLY); ev_file, O_RDONLY);
if (!filp) { if (IS_ERR(filp))
ret = -ENFILE; kfree(ev_file);
goto err_fd;
}
return filp; return filp;
err_fd:
put_unused_fd(*fd);
err:
kfree(ev_file);
return ERR_PTR(ret);
} }
/* /*

View file

@ -1050,7 +1050,7 @@ static void invalidate_sub(struct fsg_lun *curlun)
unsigned long rc; unsigned long rc;
rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
} }
static int do_verify(struct fsg_common *common) static int do_verify(struct fsg_common *common)

View file

@ -1448,7 +1448,7 @@ static void invalidate_sub(struct fsg_lun *curlun)
unsigned long rc; unsigned long rc;
rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); rc = invalidate_mapping_pages(inode->i_mapping, 0, -1);
VLDBG(curlun, "invalidate_inode_pages -> %ld\n", rc); VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc);
} }
static int do_verify(struct fsg_dev *fsg) static int do_verify(struct fsg_dev *fsg)

View file

@ -60,11 +60,6 @@ do { \
current->pid, __func__, ##args); \ current->pid, __func__, ##args); \
} while (0) } while (0)
struct rehash_entry {
struct task_struct *task;
struct list_head list;
};
/* Unified info structure. This is pointed to by both the dentry and /* Unified info structure. This is pointed to by both the dentry and
inode structures. Each file in the filesystem has an instance of this inode structures. Each file in the filesystem has an instance of this
structure. It holds a reference to the dentry, so dentries are never structure. It holds a reference to the dentry, so dentries are never
@ -81,7 +76,6 @@ struct autofs_info {
struct list_head active; struct list_head active;
int active_count; int active_count;
struct list_head rehash_list;
struct list_head expiring; struct list_head expiring;
@ -104,7 +98,6 @@ struct autofs_info {
#define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */ #define AUTOFS_INF_EXPIRING (1<<0) /* dentry is in the process of expiring */
#define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */ #define AUTOFS_INF_MOUNTPOINT (1<<1) /* mountpoint status for direct expire */
#define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */ #define AUTOFS_INF_PENDING (1<<2) /* dentry pending mount */
#define AUTOFS_INF_REHASH (1<<3) /* dentry in transit to ->lookup() */
struct autofs_wait_queue { struct autofs_wait_queue {
wait_queue_head_t queue; wait_queue_head_t queue;

View file

@ -544,10 +544,9 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
goto out; goto out;
devid = new_encode_dev(path.mnt->mnt_sb->s_dev); devid = new_encode_dev(path.mnt->mnt_sb->s_dev);
err = 0; err = 0;
if (path.dentry->d_inode && if (path.mnt->mnt_root == path.dentry) {
path.mnt->mnt_root == path.dentry) {
err = 1; err = 1;
magic = path.dentry->d_inode->i_sb->s_magic; magic = path.mnt->mnt_sb->s_magic;
} }
} else { } else {
dev_t dev = sbi->sb->s_dev; dev_t dev = sbi->sb->s_dev;
@ -560,10 +559,8 @@ static int autofs_dev_ioctl_ismountpoint(struct file *fp,
err = have_submounts(path.dentry); err = have_submounts(path.dentry);
if (path.mnt->mnt_mountpoint != path.mnt->mnt_root) { if (follow_down(&path))
if (follow_down(&path)) magic = path.mnt->mnt_sb->s_magic;
magic = path.mnt->mnt_sb->s_magic;
}
} }
param->ismountpoint.out.devid = devid; param->ismountpoint.out.devid = devid;

View file

@ -279,7 +279,6 @@ struct dentry *autofs4_expire_direct(struct super_block *sb,
root->d_mounted--; root->d_mounted--;
} }
ino->flags |= AUTOFS_INF_EXPIRING; ino->flags |= AUTOFS_INF_EXPIRING;
autofs4_add_expiring(root);
init_completion(&ino->expire_complete); init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
return root; return root;
@ -407,7 +406,6 @@ found:
expired, (int)expired->d_name.len, expired->d_name.name); expired, (int)expired->d_name.len, expired->d_name.name);
ino = autofs4_dentry_ino(expired); ino = autofs4_dentry_ino(expired);
ino->flags |= AUTOFS_INF_EXPIRING; ino->flags |= AUTOFS_INF_EXPIRING;
autofs4_add_expiring(expired);
init_completion(&ino->expire_complete); init_completion(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
@ -435,7 +433,7 @@ int autofs4_expire_wait(struct dentry *dentry)
DPRINTK("expire done status=%d", status); DPRINTK("expire done status=%d", status);
if (d_unhashed(dentry) && IS_DEADDIR(dentry->d_inode)) if (d_unhashed(dentry))
return -EAGAIN; return -EAGAIN;
return status; return status;
@ -475,7 +473,6 @@ int autofs4_expire_run(struct super_block *sb,
spin_lock(&sbi->fs_lock); spin_lock(&sbi->fs_lock);
ino = autofs4_dentry_ino(dentry); ino = autofs4_dentry_ino(dentry);
ino->flags &= ~AUTOFS_INF_EXPIRING; ino->flags &= ~AUTOFS_INF_EXPIRING;
autofs4_del_expiring(dentry);
complete_all(&ino->expire_complete); complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
@ -506,7 +503,6 @@ int autofs4_do_expire_multi(struct super_block *sb, struct vfsmount *mnt,
ino->flags &= ~AUTOFS_INF_MOUNTPOINT; ino->flags &= ~AUTOFS_INF_MOUNTPOINT;
} }
ino->flags &= ~AUTOFS_INF_EXPIRING; ino->flags &= ~AUTOFS_INF_EXPIRING;
autofs4_del_expiring(dentry);
complete_all(&ino->expire_complete); complete_all(&ino->expire_complete);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
dput(dentry); dput(dentry);

View file

@ -49,7 +49,6 @@ struct autofs_info *autofs4_init_ino(struct autofs_info *ino,
ino->dentry = NULL; ino->dentry = NULL;
ino->size = 0; ino->size = 0;
INIT_LIST_HEAD(&ino->active); INIT_LIST_HEAD(&ino->active);
INIT_LIST_HEAD(&ino->rehash_list);
ino->active_count = 0; ino->active_count = 0;
INIT_LIST_HEAD(&ino->expiring); INIT_LIST_HEAD(&ino->expiring);
atomic_set(&ino->count, 0); atomic_set(&ino->count, 0);
@ -97,63 +96,6 @@ void autofs4_free_ino(struct autofs_info *ino)
kfree(ino); kfree(ino);
} }
/*
* Deal with the infamous "Busy inodes after umount ..." message.
*
* Clean up the dentry tree. This happens with autofs if the user
* space program goes away due to a SIGKILL, SIGSEGV etc.
*/
static void autofs4_force_release(struct autofs_sb_info *sbi)
{
struct dentry *this_parent = sbi->sb->s_root;
struct list_head *next;
if (!sbi->sb->s_root)
return;
spin_lock(&dcache_lock);
repeat:
next = this_parent->d_subdirs.next;
resume:
while (next != &this_parent->d_subdirs) {
struct dentry *dentry = list_entry(next, struct dentry, d_u.d_child);
/* Negative dentry - don`t care */
if (!simple_positive(dentry)) {
next = next->next;
continue;
}
if (!list_empty(&dentry->d_subdirs)) {
this_parent = dentry;
goto repeat;
}
next = next->next;
spin_unlock(&dcache_lock);
DPRINTK("dentry %p %.*s",
dentry, (int)dentry->d_name.len, dentry->d_name.name);
dput(dentry);
spin_lock(&dcache_lock);
}
if (this_parent != sbi->sb->s_root) {
struct dentry *dentry = this_parent;
next = this_parent->d_u.d_child.next;
this_parent = this_parent->d_parent;
spin_unlock(&dcache_lock);
DPRINTK("parent dentry %p %.*s",
dentry, (int)dentry->d_name.len, dentry->d_name.name);
dput(dentry);
spin_lock(&dcache_lock);
goto resume;
}
spin_unlock(&dcache_lock);
}
void autofs4_kill_sb(struct super_block *sb) void autofs4_kill_sb(struct super_block *sb)
{ {
struct autofs_sb_info *sbi = autofs4_sbi(sb); struct autofs_sb_info *sbi = autofs4_sbi(sb);
@ -170,15 +112,12 @@ void autofs4_kill_sb(struct super_block *sb)
/* Free wait queues, close pipe */ /* Free wait queues, close pipe */
autofs4_catatonic_mode(sbi); autofs4_catatonic_mode(sbi);
/* Clean up and release dangling references */
autofs4_force_release(sbi);
sb->s_fs_info = NULL; sb->s_fs_info = NULL;
kfree(sbi); kfree(sbi);
out_kill_sb: out_kill_sb:
DPRINTK("shutting down"); DPRINTK("shutting down");
kill_anon_super(sb); kill_litter_super(sb);
} }
static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt) static int autofs4_show_options(struct seq_file *m, struct vfsmount *mnt)

View file

@ -104,99 +104,6 @@ static void autofs4_del_active(struct dentry *dentry)
return; return;
} }
static void autofs4_add_rehash_entry(struct autofs_info *ino,
struct rehash_entry *entry)
{
entry->task = current;
INIT_LIST_HEAD(&entry->list);
list_add(&entry->list, &ino->rehash_list);
return;
}
static void autofs4_remove_rehash_entry(struct autofs_info *ino)
{
struct list_head *head = &ino->rehash_list;
struct rehash_entry *entry;
list_for_each_entry(entry, head, list) {
if (entry->task == current) {
list_del(&entry->list);
kfree(entry);
break;
}
}
return;
}
static void autofs4_remove_rehash_entrys(struct autofs_info *ino)
{
struct autofs_sb_info *sbi = ino->sbi;
struct rehash_entry *entry, *next;
struct list_head *head;
spin_lock(&sbi->fs_lock);
spin_lock(&sbi->lookup_lock);
if (!(ino->flags & AUTOFS_INF_REHASH)) {
spin_unlock(&sbi->lookup_lock);
spin_unlock(&sbi->fs_lock);
return;
}
ino->flags &= ~AUTOFS_INF_REHASH;
head = &ino->rehash_list;
list_for_each_entry_safe(entry, next, head, list) {
list_del(&entry->list);
kfree(entry);
}
spin_unlock(&sbi->lookup_lock);
spin_unlock(&sbi->fs_lock);
dput(ino->dentry);
return;
}
static void autofs4_revalidate_drop(struct dentry *dentry,
struct rehash_entry *entry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
/*
* Add to the active list so we can pick this up in
* ->lookup(). Also add an entry to a rehash list so
* we know when there are no dentrys in flight so we
* know when we can rehash the dentry.
*/
spin_lock(&sbi->lookup_lock);
if (list_empty(&ino->active))
list_add(&ino->active, &sbi->active_list);
autofs4_add_rehash_entry(ino, entry);
spin_unlock(&sbi->lookup_lock);
if (!(ino->flags & AUTOFS_INF_REHASH)) {
ino->flags |= AUTOFS_INF_REHASH;
dget(dentry);
spin_lock(&dentry->d_lock);
__d_drop(dentry);
spin_unlock(&dentry->d_lock);
}
return;
}
static void autofs4_revalidate_rehash(struct dentry *dentry)
{
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry);
if (ino->flags & AUTOFS_INF_REHASH) {
spin_lock(&sbi->lookup_lock);
autofs4_remove_rehash_entry(ino);
if (list_empty(&ino->rehash_list)) {
spin_unlock(&sbi->lookup_lock);
ino->flags &= ~AUTOFS_INF_REHASH;
d_rehash(dentry);
dput(ino->dentry);
} else
spin_unlock(&sbi->lookup_lock);
}
return;
}
static unsigned int autofs4_need_mount(unsigned int flags) static unsigned int autofs4_need_mount(unsigned int flags)
{ {
unsigned int res = 0; unsigned int res = 0;
@ -236,7 +143,7 @@ out:
return dcache_dir_open(inode, file); return dcache_dir_open(inode, file);
} }
static int try_to_fill_dentry(struct dentry *dentry) static int try_to_fill_dentry(struct dentry *dentry, int flags)
{ {
struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb); struct autofs_sb_info *sbi = autofs4_sbi(dentry->d_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry); struct autofs_info *ino = autofs4_dentry_ino(dentry);
@ -249,17 +156,55 @@ static int try_to_fill_dentry(struct dentry *dentry)
* Wait for a pending mount, triggering one if there * Wait for a pending mount, triggering one if there
* isn't one already * isn't one already
*/ */
DPRINTK("waiting for mount name=%.*s", if (dentry->d_inode == NULL) {
dentry->d_name.len, dentry->d_name.name); DPRINTK("waiting for mount name=%.*s",
dentry->d_name.len, dentry->d_name.name);
status = autofs4_wait(sbi, dentry, NFY_MOUNT); status = autofs4_wait(sbi, dentry, NFY_MOUNT);
DPRINTK("mount done status=%d", status); DPRINTK("mount done status=%d", status);
/* Update expiry counter */ /* Turn this into a real negative dentry? */
ino->last_used = jiffies; if (status == -ENOENT) {
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
return status;
} else if (status) {
/* Return a negative dentry, but leave it "pending" */
return status;
}
/* Trigger mount for path component or follow link */
} else if (ino->flags & AUTOFS_INF_PENDING ||
autofs4_need_mount(flags) ||
current->link_count) {
DPRINTK("waiting for mount name=%.*s",
dentry->d_name.len, dentry->d_name.name);
return status; spin_lock(&sbi->fs_lock);
ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
status = autofs4_wait(sbi, dentry, NFY_MOUNT);
DPRINTK("mount done status=%d", status);
if (status) {
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
return status;
}
}
/* Initialize expiry counter after successful mount */
if (ino)
ino->last_used = jiffies;
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
return 0;
} }
/* For autofs direct mounts the follow link triggers the mount */ /* For autofs direct mounts the follow link triggers the mount */
@ -313,16 +258,10 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd)
*/ */
if (ino->flags & AUTOFS_INF_PENDING || if (ino->flags & AUTOFS_INF_PENDING ||
(!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) { (!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs))) {
ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
status = try_to_fill_dentry(dentry); status = try_to_fill_dentry(dentry, 0);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
if (status) if (status)
goto out_error; goto out_error;
@ -361,47 +300,18 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
{ {
struct inode *dir = dentry->d_parent->d_inode; struct inode *dir = dentry->d_parent->d_inode;
struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb); struct autofs_sb_info *sbi = autofs4_sbi(dir->i_sb);
struct autofs_info *ino = autofs4_dentry_ino(dentry); int oz_mode = autofs4_oz_mode(sbi);
struct rehash_entry *entry;
int flags = nd ? nd->flags : 0; int flags = nd ? nd->flags : 0;
unsigned int mutex_aquired; int status = 1;
DPRINTK("name = %.*s oz_mode = %d",
dentry->d_name.len, dentry->d_name.name, oz_mode);
/* Daemon never causes a mount to trigger */
if (autofs4_oz_mode(sbi))
return 1;
entry = kmalloc(sizeof(struct rehash_entry), GFP_KERNEL);
if (!entry)
return -ENOMEM;
mutex_aquired = mutex_trylock(&dir->i_mutex);
spin_lock(&sbi->fs_lock);
spin_lock(&dcache_lock);
/* Pending dentry */ /* Pending dentry */
spin_lock(&sbi->fs_lock);
if (autofs4_ispending(dentry)) { if (autofs4_ispending(dentry)) {
int status; /* The daemon never causes a mount to trigger */
/*
* We can only unhash and send this to ->lookup() if
* the directory mutex is held over d_revalidate() and
* ->lookup(). This prevents the VFS from incorrectly
* seeing the dentry as non-existent.
*/
ino->flags |= AUTOFS_INF_PENDING;
if (!mutex_aquired) {
autofs4_revalidate_drop(dentry, entry);
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
return 0;
}
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
mutex_unlock(&dir->i_mutex);
kfree(entry); if (oz_mode)
return 1;
/* /*
* If the directory has gone away due to an expire * If the directory has gone away due to an expire
@ -415,82 +325,45 @@ static int autofs4_revalidate(struct dentry *dentry, struct nameidata *nd)
* A zero status is success otherwise we have a * A zero status is success otherwise we have a
* negative error code. * negative error code.
*/ */
status = try_to_fill_dentry(dentry); status = try_to_fill_dentry(dentry, flags);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
if (status == 0) if (status == 0)
return 1; return 1;
return status; return status;
} }
spin_unlock(&sbi->fs_lock);
/* Negative dentry.. invalidate if "old" */
if (dentry->d_inode == NULL)
return 0;
/* Check for a non-mountpoint directory with no contents */ /* Check for a non-mountpoint directory with no contents */
spin_lock(&dcache_lock);
if (S_ISDIR(dentry->d_inode->i_mode) && if (S_ISDIR(dentry->d_inode->i_mode) &&
!d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) { !d_mountpoint(dentry) && list_empty(&dentry->d_subdirs)) {
DPRINTK("dentry=%p %.*s, emptydir", DPRINTK("dentry=%p %.*s, emptydir",
dentry, dentry->d_name.len, dentry->d_name.name); dentry, dentry->d_name.len, dentry->d_name.name);
spin_unlock(&dcache_lock);
if (autofs4_need_mount(flags) || current->link_count) { /* The daemon never causes a mount to trigger */
int status; if (oz_mode)
return 1;
/* /*
* We can only unhash and send this to ->lookup() if * A zero status is success otherwise we have a
* the directory mutex is held over d_revalidate() and * negative error code.
* ->lookup(). This prevents the VFS from incorrectly */
* seeing the dentry as non-existent. status = try_to_fill_dentry(dentry, flags);
*/ if (status == 0)
ino->flags |= AUTOFS_INF_PENDING; return 1;
if (!mutex_aquired) {
autofs4_revalidate_drop(dentry, entry);
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
return 0;
}
spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
mutex_unlock(&dir->i_mutex);
kfree(entry);
/* return status;
* A zero status is success otherwise we have a
* negative error code.
*/
status = try_to_fill_dentry(dentry);
spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock);
if (status == 0)
return 1;
return status;
}
} }
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
spin_unlock(&sbi->fs_lock);
if (mutex_aquired)
mutex_unlock(&dir->i_mutex);
kfree(entry);
return 1; return 1;
} }
static void autofs4_free_rehash_entrys(struct autofs_info *inf)
{
struct list_head *head = &inf->rehash_list;
struct rehash_entry *entry, *next;
list_for_each_entry_safe(entry, next, head, list) {
list_del(&entry->list);
kfree(entry);
}
}
void autofs4_dentry_release(struct dentry *de) void autofs4_dentry_release(struct dentry *de)
{ {
struct autofs_info *inf; struct autofs_info *inf;
@ -509,8 +382,6 @@ void autofs4_dentry_release(struct dentry *de)
list_del(&inf->active); list_del(&inf->active);
if (!list_empty(&inf->expiring)) if (!list_empty(&inf->expiring))
list_del(&inf->expiring); list_del(&inf->expiring);
if (!list_empty(&inf->rehash_list))
autofs4_free_rehash_entrys(inf);
spin_unlock(&sbi->lookup_lock); spin_unlock(&sbi->lookup_lock);
} }
@ -543,7 +414,6 @@ static struct dentry *autofs4_lookup_active(struct dentry *dentry)
const unsigned char *str = name->name; const unsigned char *str = name->name;
struct list_head *p, *head; struct list_head *p, *head;
restart:
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
spin_lock(&sbi->lookup_lock); spin_lock(&sbi->lookup_lock);
head = &sbi->active_list; head = &sbi->active_list;
@ -561,19 +431,6 @@ restart:
if (atomic_read(&active->d_count) == 0) if (atomic_read(&active->d_count) == 0)
goto next; goto next;
if (active->d_inode && IS_DEADDIR(active->d_inode)) {
if (!list_empty(&ino->rehash_list)) {
dget(active);
spin_unlock(&active->d_lock);
spin_unlock(&sbi->lookup_lock);
spin_unlock(&dcache_lock);
autofs4_remove_rehash_entrys(ino);
dput(active);
goto restart;
}
goto next;
}
qstr = &active->d_name; qstr = &active->d_name;
if (active->d_name.hash != hash) if (active->d_name.hash != hash)
@ -586,11 +443,13 @@ restart:
if (memcmp(qstr->name, str, len)) if (memcmp(qstr->name, str, len))
goto next; goto next;
dget(active); if (d_unhashed(active)) {
spin_unlock(&active->d_lock); dget(active);
spin_unlock(&sbi->lookup_lock); spin_unlock(&active->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&sbi->lookup_lock);
return active; spin_unlock(&dcache_lock);
return active;
}
next: next:
spin_unlock(&active->d_lock); spin_unlock(&active->d_lock);
} }
@ -639,11 +498,13 @@ static struct dentry *autofs4_lookup_expiring(struct dentry *dentry)
if (memcmp(qstr->name, str, len)) if (memcmp(qstr->name, str, len))
goto next; goto next;
dget(expiring); if (d_unhashed(expiring)) {
spin_unlock(&expiring->d_lock); dget(expiring);
spin_unlock(&sbi->lookup_lock); spin_unlock(&expiring->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&sbi->lookup_lock);
return expiring; spin_unlock(&dcache_lock);
return expiring;
}
next: next:
spin_unlock(&expiring->d_lock); spin_unlock(&expiring->d_lock);
} }
@ -653,48 +514,6 @@ next:
return NULL; return NULL;
} }
static struct autofs_info *init_new_dentry(struct autofs_sb_info *sbi,
struct dentry *dentry, int oz_mode)
{
struct autofs_info *ino;
/*
* Mark the dentry incomplete but don't hash it. We do this
* to serialize our inode creation operations (symlink and
* mkdir) which prevents deadlock during the callback to
* the daemon. Subsequent user space lookups for the same
* dentry are placed on the wait queue while the daemon
* itself is allowed passage unresticted so the create
* operation itself can then hash the dentry. Finally,
* we check for the hashed dentry and return the newly
* hashed dentry.
*/
dentry->d_op = &autofs4_root_dentry_operations;
/*
* And we need to ensure that the same dentry is used for
* all following lookup calls until it is hashed so that
* the dentry flags are persistent throughout the request.
*/
ino = autofs4_init_ino(NULL, sbi, 0555);
if (!ino)
return ERR_PTR(-ENOMEM);
dentry->d_fsdata = ino;
ino->dentry = dentry;
/*
* Only set the mount pending flag for new dentrys not created
* by the daemon.
*/
if (!oz_mode)
ino->flags |= AUTOFS_INF_PENDING;
d_instantiate(dentry, NULL);
return ino;
}
/* Lookups in the root directory */ /* Lookups in the root directory */
static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{ {
@ -702,7 +521,6 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
struct autofs_info *ino; struct autofs_info *ino;
struct dentry *expiring, *active; struct dentry *expiring, *active;
int oz_mode; int oz_mode;
int status = 0;
DPRINTK("name = %.*s", DPRINTK("name = %.*s",
dentry->d_name.len, dentry->d_name.name); dentry->d_name.len, dentry->d_name.name);
@ -717,26 +535,44 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d", DPRINTK("pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d",
current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode); current->pid, task_pgrp_nr(current), sbi->catatonic, oz_mode);
spin_lock(&sbi->fs_lock);
active = autofs4_lookup_active(dentry); active = autofs4_lookup_active(dentry);
if (active) { if (active) {
dentry = active; dentry = active;
ino = autofs4_dentry_ino(dentry); ino = autofs4_dentry_ino(dentry);
/* If this came from revalidate, rehash it */
autofs4_revalidate_rehash(dentry);
spin_unlock(&sbi->fs_lock);
} else { } else {
spin_unlock(&sbi->fs_lock); /*
ino = init_new_dentry(sbi, dentry, oz_mode); * Mark the dentry incomplete but don't hash it. We do this
if (IS_ERR(ino)) * to serialize our inode creation operations (symlink and
return (struct dentry *) ino; * mkdir) which prevents deadlock during the callback to
* the daemon. Subsequent user space lookups for the same
* dentry are placed on the wait queue while the daemon
* itself is allowed passage unresticted so the create
* operation itself can then hash the dentry. Finally,
* we check for the hashed dentry and return the newly
* hashed dentry.
*/
dentry->d_op = &autofs4_root_dentry_operations;
/*
* And we need to ensure that the same dentry is used for
* all following lookup calls until it is hashed so that
* the dentry flags are persistent throughout the request.
*/
ino = autofs4_init_ino(NULL, sbi, 0555);
if (!ino)
return ERR_PTR(-ENOMEM);
dentry->d_fsdata = ino;
ino->dentry = dentry;
autofs4_add_active(dentry);
d_instantiate(dentry, NULL);
} }
autofs4_add_active(dentry);
if (!oz_mode) { if (!oz_mode) {
expiring = autofs4_lookup_expiring(dentry);
mutex_unlock(&dir->i_mutex); mutex_unlock(&dir->i_mutex);
expiring = autofs4_lookup_expiring(dentry);
if (expiring) { if (expiring) {
/* /*
* If we are racing with expire the request might not * If we are racing with expire the request might not
@ -744,22 +580,23 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
* so it must have been successful, so just wait for it. * so it must have been successful, so just wait for it.
*/ */
autofs4_expire_wait(expiring); autofs4_expire_wait(expiring);
autofs4_del_expiring(expiring);
dput(expiring); dput(expiring);
} }
status = try_to_fill_dentry(dentry);
mutex_lock(&dir->i_mutex);
spin_lock(&sbi->fs_lock); spin_lock(&sbi->fs_lock);
ino->flags &= ~AUTOFS_INF_PENDING; ino->flags |= AUTOFS_INF_PENDING;
spin_unlock(&sbi->fs_lock); spin_unlock(&sbi->fs_lock);
if (dentry->d_op && dentry->d_op->d_revalidate)
(dentry->d_op->d_revalidate)(dentry, nd);
mutex_lock(&dir->i_mutex);
} }
autofs4_del_active(dentry);
/* /*
* If we had a mount fail, check if we had to handle * If we are still pending, check if we had to handle
* a signal. If so we can force a restart.. * a signal. If so we can force a restart..
*/ */
if (status) { if (ino->flags & AUTOFS_INF_PENDING) {
/* See if we were interrupted */ /* See if we were interrupted */
if (signal_pending(current)) { if (signal_pending(current)) {
sigset_t *sigset = &current->pending.signal; sigset_t *sigset = &current->pending.signal;
@ -771,46 +608,43 @@ static struct dentry *autofs4_lookup(struct inode *dir, struct dentry *dentry, s
return ERR_PTR(-ERESTARTNOINTR); return ERR_PTR(-ERESTARTNOINTR);
} }
} }
} if (!oz_mode) {
spin_lock(&sbi->fs_lock);
/* ino->flags &= ~AUTOFS_INF_PENDING;
* User space can (and has done in the past) remove and re-create spin_unlock(&sbi->fs_lock);
* this directory during the callback. This can leave us with an
* unhashed dentry, but a successful mount! So we need to
* perform another cached lookup in case the dentry now exists.
*/
if (!oz_mode && !have_submounts(dentry)) {
struct dentry *new;
new = d_lookup(dentry->d_parent, &dentry->d_name);
if (new) {
if (active)
dput(active);
return new;
} else {
if (!status)
status = -ENOENT;
} }
} }
/* /*
* If we had a mount failure, return status to user space. * If this dentry is unhashed, then we shouldn't honour this
* If the mount succeeded and we used a dentry from the active queue * lookup. Returning ENOENT here doesn't do the right thing
* return it. * for all system calls, but it should be OK for the operations
* we permit from an autofs.
*/ */
if (status) { if (!oz_mode && d_unhashed(dentry)) {
dentry = ERR_PTR(status); /*
* A user space application can (and has done in the past)
* remove and re-create this directory during the callback.
* This can leave us with an unhashed dentry, but a
* successful mount! So we need to perform another
* cached lookup in case the dentry now exists.
*/
struct dentry *parent = dentry->d_parent;
struct dentry *new = d_lookup(parent, &dentry->d_name);
if (new != NULL)
dentry = new;
else
dentry = ERR_PTR(-ENOENT);
if (active) if (active)
dput(active); dput(active);
return dentry; return dentry;
} else {
/*
* Valid successful mount, return active dentry or NULL
* for a new dentry.
*/
if (active)
return active;
} }
if (active)
return active;
return NULL; return NULL;
} }
@ -834,6 +668,8 @@ static int autofs4_dir_symlink(struct inode *dir,
if (!ino) if (!ino)
return -ENOMEM; return -ENOMEM;
autofs4_del_active(dentry);
ino->size = strlen(symname); ino->size = strlen(symname);
cp = kmalloc(ino->size + 1, GFP_KERNEL); cp = kmalloc(ino->size + 1, GFP_KERNEL);
if (!cp) { if (!cp) {
@ -910,6 +746,7 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
dir->i_mtime = CURRENT_TIME; dir->i_mtime = CURRENT_TIME;
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
autofs4_add_expiring(dentry);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
@ -935,6 +772,7 @@ static int autofs4_dir_rmdir(struct inode *dir, struct dentry *dentry)
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
return -ENOTEMPTY; return -ENOTEMPTY;
} }
autofs4_add_expiring(dentry);
spin_lock(&dentry->d_lock); spin_lock(&dentry->d_lock);
__d_drop(dentry); __d_drop(dentry);
spin_unlock(&dentry->d_lock); spin_unlock(&dentry->d_lock);
@ -972,6 +810,8 @@ static int autofs4_dir_mkdir(struct inode *dir, struct dentry *dentry, int mode)
if (!ino) if (!ino)
return -ENOMEM; return -ENOMEM;
autofs4_del_active(dentry);
inode = autofs4_get_inode(dir->i_sb, ino); inode = autofs4_get_inode(dir->i_sb, ino);
if (!inode) { if (!inode) {
if (!dentry->d_fsdata) if (!dentry->d_fsdata)

View file

@ -2289,9 +2289,9 @@ cifs_oplock_break(struct slow_work *work)
if (inode && S_ISREG(inode->i_mode)) { if (inode && S_ISREG(inode->i_mode)) {
#ifdef CONFIG_CIFS_EXPERIMENTAL #ifdef CONFIG_CIFS_EXPERIMENTAL
if (cinode->clientCanCacheAll == 0) if (cinode->clientCanCacheAll == 0)
break_lease(inode, FMODE_READ); break_lease(inode, O_RDONLY);
else if (cinode->clientCanCacheRead == 0) else if (cinode->clientCanCacheRead == 0)
break_lease(inode, FMODE_WRITE); break_lease(inode, O_WRONLY);
#endif #endif
rc = filemap_fdatawrite(inode->i_mapping); rc = filemap_fdatawrite(inode->i_mapping);
if (cinode->clientCanCacheRead == 0) { if (cinode->clientCanCacheRead == 0) {

View file

@ -257,6 +257,7 @@ kill_it:
if (dentry) if (dentry)
goto repeat; goto repeat;
} }
EXPORT_SYMBOL(dput);
/** /**
* d_invalidate - invalidate a dentry * d_invalidate - invalidate a dentry
@ -314,6 +315,7 @@ int d_invalidate(struct dentry * dentry)
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
return 0; return 0;
} }
EXPORT_SYMBOL(d_invalidate);
/* This should be called _only_ with dcache_lock held */ /* This should be called _only_ with dcache_lock held */
@ -328,6 +330,7 @@ struct dentry * dget_locked(struct dentry *dentry)
{ {
return __dget_locked(dentry); return __dget_locked(dentry);
} }
EXPORT_SYMBOL(dget_locked);
/** /**
* d_find_alias - grab a hashed alias of inode * d_find_alias - grab a hashed alias of inode
@ -384,6 +387,7 @@ struct dentry * d_find_alias(struct inode *inode)
} }
return de; return de;
} }
EXPORT_SYMBOL(d_find_alias);
/* /*
* Try to kill dentries associated with this inode. * Try to kill dentries associated with this inode.
@ -408,6 +412,7 @@ restart:
} }
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
EXPORT_SYMBOL(d_prune_aliases);
/* /*
* Throw away a dentry - free the inode, dput the parent. This requires that * Throw away a dentry - free the inode, dput the parent. This requires that
@ -610,6 +615,7 @@ void shrink_dcache_sb(struct super_block * sb)
{ {
__shrink_dcache_sb(sb, NULL, 0); __shrink_dcache_sb(sb, NULL, 0);
} }
EXPORT_SYMBOL(shrink_dcache_sb);
/* /*
* destroy a single subtree of dentries for unmount * destroy a single subtree of dentries for unmount
@ -792,6 +798,7 @@ positive:
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
return 1; return 1;
} }
EXPORT_SYMBOL(have_submounts);
/* /*
* Search the dentry child list for the specified parent, * Search the dentry child list for the specified parent,
@ -876,6 +883,7 @@ void shrink_dcache_parent(struct dentry * parent)
while ((found = select_parent(parent)) != 0) while ((found = select_parent(parent)) != 0)
__shrink_dcache_sb(sb, &found, 0); __shrink_dcache_sb(sb, &found, 0);
} }
EXPORT_SYMBOL(shrink_dcache_parent);
/* /*
* Scan `nr' dentries and return the number which remain. * Scan `nr' dentries and return the number which remain.
@ -968,6 +976,7 @@ struct dentry *d_alloc(struct dentry * parent, const struct qstr *name)
return dentry; return dentry;
} }
EXPORT_SYMBOL(d_alloc);
struct dentry *d_alloc_name(struct dentry *parent, const char *name) struct dentry *d_alloc_name(struct dentry *parent, const char *name)
{ {
@ -1012,6 +1021,7 @@ void d_instantiate(struct dentry *entry, struct inode * inode)
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
security_d_instantiate(entry, inode); security_d_instantiate(entry, inode);
} }
EXPORT_SYMBOL(d_instantiate);
/** /**
* d_instantiate_unique - instantiate a non-aliased dentry * d_instantiate_unique - instantiate a non-aliased dentry
@ -1108,6 +1118,7 @@ struct dentry * d_alloc_root(struct inode * root_inode)
} }
return res; return res;
} }
EXPORT_SYMBOL(d_alloc_root);
static inline struct hlist_head *d_hash(struct dentry *parent, static inline struct hlist_head *d_hash(struct dentry *parent,
unsigned long hash) unsigned long hash)
@ -1211,7 +1222,6 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED)); BUG_ON(!(new->d_flags & DCACHE_DISCONNECTED));
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
security_d_instantiate(new, inode); security_d_instantiate(new, inode);
d_rehash(dentry);
d_move(new, dentry); d_move(new, dentry);
iput(inode); iput(inode);
} else { } else {
@ -1225,6 +1235,7 @@ struct dentry *d_splice_alias(struct inode *inode, struct dentry *dentry)
d_add(dentry, inode); d_add(dentry, inode);
return new; return new;
} }
EXPORT_SYMBOL(d_splice_alias);
/** /**
* d_add_ci - lookup or allocate new dentry with case-exact name * d_add_ci - lookup or allocate new dentry with case-exact name
@ -1314,6 +1325,7 @@ err_out:
iput(inode); iput(inode);
return ERR_PTR(error); return ERR_PTR(error);
} }
EXPORT_SYMBOL(d_add_ci);
/** /**
* d_lookup - search for a dentry * d_lookup - search for a dentry
@ -1357,6 +1369,7 @@ struct dentry * d_lookup(struct dentry * parent, struct qstr * name)
} while (read_seqretry(&rename_lock, seq)); } while (read_seqretry(&rename_lock, seq));
return dentry; return dentry;
} }
EXPORT_SYMBOL(d_lookup);
struct dentry * __d_lookup(struct dentry * parent, struct qstr * name) struct dentry * __d_lookup(struct dentry * parent, struct qstr * name)
{ {
@ -1483,6 +1496,7 @@ int d_validate(struct dentry *dentry, struct dentry *dparent)
out: out:
return 0; return 0;
} }
EXPORT_SYMBOL(d_validate);
/* /*
* When a file is deleted, we have two options: * When a file is deleted, we have two options:
@ -1528,6 +1542,7 @@ void d_delete(struct dentry * dentry)
fsnotify_nameremove(dentry, isdir); fsnotify_nameremove(dentry, isdir);
} }
EXPORT_SYMBOL(d_delete);
static void __d_rehash(struct dentry * entry, struct hlist_head *list) static void __d_rehash(struct dentry * entry, struct hlist_head *list)
{ {
@ -1556,6 +1571,7 @@ void d_rehash(struct dentry * entry)
spin_unlock(&entry->d_lock); spin_unlock(&entry->d_lock);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
EXPORT_SYMBOL(d_rehash);
/* /*
* When switching names, the actual string doesn't strictly have to * When switching names, the actual string doesn't strictly have to
@ -1702,6 +1718,7 @@ void d_move(struct dentry * dentry, struct dentry * target)
d_move_locked(dentry, target); d_move_locked(dentry, target);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
} }
EXPORT_SYMBOL(d_move);
/** /**
* d_ancestor - search for an ancestor * d_ancestor - search for an ancestor
@ -1868,6 +1885,7 @@ shouldnt_be_hashed:
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
BUG(); BUG();
} }
EXPORT_SYMBOL_GPL(d_materialise_unique);
static int prepend(char **buffer, int *buflen, const char *str, int namelen) static int prepend(char **buffer, int *buflen, const char *str, int namelen)
{ {
@ -2005,6 +2023,7 @@ char *d_path(const struct path *path, char *buf, int buflen)
path_put(&root); path_put(&root);
return res; return res;
} }
EXPORT_SYMBOL(d_path);
/* /*
* Helper function for dentry_operations.d_dname() members * Helper function for dentry_operations.d_dname() members
@ -2171,6 +2190,30 @@ int is_subdir(struct dentry *new_dentry, struct dentry *old_dentry)
return result; return result;
} }
int path_is_under(struct path *path1, struct path *path2)
{
struct vfsmount *mnt = path1->mnt;
struct dentry *dentry = path1->dentry;
int res;
spin_lock(&vfsmount_lock);
if (mnt != path2->mnt) {
for (;;) {
if (mnt->mnt_parent == mnt) {
spin_unlock(&vfsmount_lock);
return 0;
}
if (mnt->mnt_parent == path2->mnt)
break;
mnt = mnt->mnt_parent;
}
dentry = mnt->mnt_mountpoint;
}
res = is_subdir(dentry, path2->dentry);
spin_unlock(&vfsmount_lock);
return res;
}
EXPORT_SYMBOL(path_is_under);
void d_genocide(struct dentry *root) void d_genocide(struct dentry *root)
{ {
struct dentry *this_parent = root; struct dentry *this_parent = root;
@ -2228,6 +2271,7 @@ ino_t find_inode_number(struct dentry *dir, struct qstr *name)
} }
return ino; return ino;
} }
EXPORT_SYMBOL(find_inode_number);
static __initdata unsigned long dhash_entries; static __initdata unsigned long dhash_entries;
static int __init set_dhash_entries(char *str) static int __init set_dhash_entries(char *str)
@ -2297,6 +2341,7 @@ static void __init dcache_init(void)
/* SLAB cache for __getname() consumers */ /* SLAB cache for __getname() consumers */
struct kmem_cache *names_cachep __read_mostly; struct kmem_cache *names_cachep __read_mostly;
EXPORT_SYMBOL(names_cachep);
EXPORT_SYMBOL(d_genocide); EXPORT_SYMBOL(d_genocide);
@ -2326,26 +2371,3 @@ void __init vfs_caches_init(unsigned long mempages)
bdev_cache_init(); bdev_cache_init();
chrdev_init(); chrdev_init();
} }
EXPORT_SYMBOL(d_alloc);
EXPORT_SYMBOL(d_alloc_root);
EXPORT_SYMBOL(d_delete);
EXPORT_SYMBOL(d_find_alias);
EXPORT_SYMBOL(d_instantiate);
EXPORT_SYMBOL(d_invalidate);
EXPORT_SYMBOL(d_lookup);
EXPORT_SYMBOL(d_move);
EXPORT_SYMBOL_GPL(d_materialise_unique);
EXPORT_SYMBOL(d_path);
EXPORT_SYMBOL(d_prune_aliases);
EXPORT_SYMBOL(d_rehash);
EXPORT_SYMBOL(d_splice_alias);
EXPORT_SYMBOL(d_add_ci);
EXPORT_SYMBOL(d_validate);
EXPORT_SYMBOL(dget_locked);
EXPORT_SYMBOL(dput);
EXPORT_SYMBOL(find_inode_number);
EXPORT_SYMBOL(have_submounts);
EXPORT_SYMBOL(names_cachep);
EXPORT_SYMBOL(shrink_dcache_parent);
EXPORT_SYMBOL(shrink_dcache_sb);

View file

@ -496,7 +496,7 @@ struct dentry *debugfs_rename(struct dentry *old_dir, struct dentry *old_dentry,
} }
d_move(old_dentry, dentry); d_move(old_dentry, dentry);
fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name, fsnotify_move(old_dir->d_inode, new_dir->d_inode, old_name,
old_dentry->d_name.name, S_ISDIR(old_dentry->d_inode->i_mode), S_ISDIR(old_dentry->d_inode->i_mode),
NULL, old_dentry); NULL, old_dentry);
fsnotify_oldname_free(old_name); fsnotify_oldname_free(old_name);
unlock_rename(new_dir, old_dir); unlock_rename(new_dir, old_dir);

View file

@ -116,11 +116,9 @@ static int ext4_file_open(struct inode * inode, struct file * filp)
* devices or filesystem images. * devices or filesystem images.
*/ */
memset(buf, 0, sizeof(buf)); memset(buf, 0, sizeof(buf));
path.mnt = mnt->mnt_parent; path.mnt = mnt;
path.dentry = mnt->mnt_mountpoint; path.dentry = mnt->mnt_root;
path_get(&path);
cp = d_path(&path, buf, sizeof(buf)); cp = d_path(&path, buf, sizeof(buf));
path_put(&path);
if (!IS_ERR(cp)) { if (!IS_ERR(cp)) {
memcpy(sbi->s_es->s_last_mounted, cp, memcpy(sbi->s_es->s_last_mounted, cp,
sizeof(sbi->s_es->s_last_mounted)); sizeof(sbi->s_es->s_last_mounted));

View file

@ -975,103 +975,12 @@ out:
return error; return error;
} }
/**
* gfs2_readlinki - return the contents of a symlink
* @ip: the symlink's inode
* @buf: a pointer to the buffer to be filled
* @len: a pointer to the length of @buf
*
* If @buf is too small, a piece of memory is kmalloc()ed and needs
* to be freed by the caller.
*
* Returns: errno
*/
static int gfs2_readlinki(struct gfs2_inode *ip, char **buf, unsigned int *len)
{
struct gfs2_holder i_gh;
struct buffer_head *dibh;
unsigned int x;
int error;
gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
error = gfs2_glock_nq(&i_gh);
if (error) {
gfs2_holder_uninit(&i_gh);
return error;
}
if (!ip->i_disksize) {
gfs2_consist_inode(ip);
error = -EIO;
goto out;
}
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error)
goto out;
x = ip->i_disksize + 1;
if (x > *len) {
*buf = kmalloc(x, GFP_NOFS);
if (!*buf) {
error = -ENOMEM;
goto out_brelse;
}
}
memcpy(*buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
*len = x;
out_brelse:
brelse(dibh);
out:
gfs2_glock_dq_uninit(&i_gh);
return error;
}
/**
* gfs2_readlink - Read the value of a symlink
* @dentry: the symlink
* @buf: the buffer to read the symlink data into
* @size: the size of the buffer
*
* Returns: errno
*/
static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,
int user_size)
{
struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
char array[GFS2_FAST_NAME_SIZE], *buf = array;
unsigned int len = GFS2_FAST_NAME_SIZE;
int error;
error = gfs2_readlinki(ip, &buf, &len);
if (error)
return error;
if (user_size > len - 1)
user_size = len - 1;
if (copy_to_user(user_buf, buf, user_size))
error = -EFAULT;
else
error = user_size;
if (buf != array)
kfree(buf);
return error;
}
/** /**
* gfs2_follow_link - Follow a symbolic link * gfs2_follow_link - Follow a symbolic link
* @dentry: The dentry of the link * @dentry: The dentry of the link
* @nd: Data that we pass to vfs_follow_link() * @nd: Data that we pass to vfs_follow_link()
* *
* This can handle symlinks of any size. It is optimised for symlinks * This can handle symlinks of any size.
* under GFS2_FAST_NAME_SIZE.
* *
* Returns: 0 on success or error code * Returns: 0 on success or error code
*/ */
@ -1079,19 +988,50 @@ static int gfs2_readlink(struct dentry *dentry, char __user *user_buf,
static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd) static void *gfs2_follow_link(struct dentry *dentry, struct nameidata *nd)
{ {
struct gfs2_inode *ip = GFS2_I(dentry->d_inode); struct gfs2_inode *ip = GFS2_I(dentry->d_inode);
char array[GFS2_FAST_NAME_SIZE], *buf = array; struct gfs2_holder i_gh;
unsigned int len = GFS2_FAST_NAME_SIZE; struct buffer_head *dibh;
unsigned int x;
char *buf;
int error; int error;
error = gfs2_readlinki(ip, &buf, &len); gfs2_holder_init(ip->i_gl, LM_ST_SHARED, 0, &i_gh);
if (!error) { error = gfs2_glock_nq(&i_gh);
error = vfs_follow_link(nd, buf); if (error) {
if (buf != array) gfs2_holder_uninit(&i_gh);
kfree(buf); nd_set_link(nd, ERR_PTR(error));
} else return NULL;
path_put(&nd->path); }
return ERR_PTR(error); if (!ip->i_disksize) {
gfs2_consist_inode(ip);
buf = ERR_PTR(-EIO);
goto out;
}
error = gfs2_meta_inode_buffer(ip, &dibh);
if (error) {
buf = ERR_PTR(error);
goto out;
}
x = ip->i_disksize + 1;
buf = kmalloc(x, GFP_NOFS);
if (!buf)
buf = ERR_PTR(-ENOMEM);
else
memcpy(buf, dibh->b_data + sizeof(struct gfs2_dinode), x);
brelse(dibh);
out:
gfs2_glock_dq_uninit(&i_gh);
nd_set_link(nd, buf);
return NULL;
}
static void gfs2_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
char *s = nd_get_link(nd);
if (!IS_ERR(s))
kfree(s);
} }
/** /**
@ -1426,8 +1366,9 @@ const struct inode_operations gfs2_dir_iops = {
}; };
const struct inode_operations gfs2_symlink_iops = { const struct inode_operations gfs2_symlink_iops = {
.readlink = gfs2_readlink, .readlink = generic_readlink,
.follow_link = gfs2_follow_link, .follow_link = gfs2_follow_link,
.put_link = gfs2_put_link,
.permission = gfs2_permission, .permission = gfs2_permission,
.setattr = gfs2_setattr, .setattr = gfs2_setattr,
.getattr = gfs2_getattr, .getattr = gfs2_getattr,

View file

@ -353,7 +353,7 @@ int hpfs_ea_read(struct super_block *s, secno a, int ano, unsigned pos,
} }
int hpfs_ea_write(struct super_block *s, secno a, int ano, unsigned pos, int hpfs_ea_write(struct super_block *s, secno a, int ano, unsigned pos,
unsigned len, char *buf) unsigned len, const char *buf)
{ {
struct buffer_head *bh; struct buffer_head *bh;
char *data; char *data;

View file

@ -20,8 +20,8 @@ static int hpfs_hash_dentry(struct dentry *dentry, struct qstr *qstr)
if (l == 1) if (qstr->name[0]=='.') goto x; if (l == 1) if (qstr->name[0]=='.') goto x;
if (l == 2) if (qstr->name[0]=='.' || qstr->name[1]=='.') goto x; if (l == 2) if (qstr->name[0]=='.' || qstr->name[1]=='.') goto x;
hpfs_adjust_length((char *)qstr->name, &l); hpfs_adjust_length(qstr->name, &l);
/*if (hpfs_chk_name((char *)qstr->name,&l))*/ /*if (hpfs_chk_name(qstr->name,&l))*/
/*return -ENAMETOOLONG;*/ /*return -ENAMETOOLONG;*/
/*return -ENOENT;*/ /*return -ENOENT;*/
x: x:
@ -38,14 +38,16 @@ static int hpfs_compare_dentry(struct dentry *dentry, struct qstr *a, struct qst
{ {
unsigned al=a->len; unsigned al=a->len;
unsigned bl=b->len; unsigned bl=b->len;
hpfs_adjust_length((char *)a->name, &al); hpfs_adjust_length(a->name, &al);
/*hpfs_adjust_length((char *)b->name, &bl);*/ /*hpfs_adjust_length(b->name, &bl);*/
/* 'a' is the qstr of an already existing dentry, so the name /* 'a' is the qstr of an already existing dentry, so the name
* must be valid. 'b' must be validated first. * must be valid. 'b' must be validated first.
*/ */
if (hpfs_chk_name((char *)b->name, &bl)) return 1; if (hpfs_chk_name(b->name, &bl))
if (hpfs_compare_names(dentry->d_sb, (char *)a->name, al, (char *)b->name, bl, 0)) return 1; return 1;
if (hpfs_compare_names(dentry->d_sb, a->name, al, b->name, bl, 0))
return 1;
return 0; return 0;
} }

View file

@ -59,7 +59,7 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
struct hpfs_dirent *de; struct hpfs_dirent *de;
int lc; int lc;
long old_pos; long old_pos;
char *tempname; unsigned char *tempname;
int c1, c2 = 0; int c1, c2 = 0;
int ret = 0; int ret = 0;
@ -158,11 +158,11 @@ static int hpfs_readdir(struct file *filp, void *dirent, filldir_t filldir)
tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3); tempname = hpfs_translate_name(inode->i_sb, de->name, de->namelen, lc, de->not_8x3);
if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) { if (filldir(dirent, tempname, de->namelen, old_pos, de->fnode, DT_UNKNOWN) < 0) {
filp->f_pos = old_pos; filp->f_pos = old_pos;
if (tempname != (char *)de->name) kfree(tempname); if (tempname != de->name) kfree(tempname);
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
goto out; goto out;
} }
if (tempname != (char *)de->name) kfree(tempname); if (tempname != de->name) kfree(tempname);
hpfs_brelse4(&qbh); hpfs_brelse4(&qbh);
} }
out: out:
@ -187,7 +187,7 @@ out:
struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
struct hpfs_dirent *de; struct hpfs_dirent *de;
@ -197,7 +197,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
struct hpfs_inode_info *hpfs_result; struct hpfs_inode_info *hpfs_result;
lock_kernel(); lock_kernel();
if ((err = hpfs_chk_name((char *)name, &len))) { if ((err = hpfs_chk_name(name, &len))) {
if (err == -ENAMETOOLONG) { if (err == -ENAMETOOLONG) {
unlock_kernel(); unlock_kernel();
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
@ -209,7 +209,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
* '.' and '..' will never be passed here. * '.' and '..' will never be passed here.
*/ */
de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *) name, len, NULL, &qbh); de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, NULL, &qbh);
/* /*
* This is not really a bailout, just means file not found. * This is not really a bailout, just means file not found.
@ -250,7 +250,7 @@ struct dentry *hpfs_lookup(struct inode *dir, struct dentry *dentry, struct name
hpfs_result = hpfs_i(result); hpfs_result = hpfs_i(result);
if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino; if (!de->directory) hpfs_result->i_parent_dir = dir->i_ino;
hpfs_decide_conv(result, (char *)name, len); hpfs_decide_conv(result, name, len);
if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) { if (de->has_acl || de->has_xtd_perm) if (!(dir->i_sb->s_flags & MS_RDONLY)) {
hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures"); hpfs_error(result->i_sb, "ACLs or XPERM found. This is probably HPFS386. This driver doesn't support it now. Send me some info on these structures");

View file

@ -158,7 +158,8 @@ static void set_last_pointer(struct super_block *s, struct dnode *d, dnode_secno
/* Add an entry to dnode and don't care if it grows over 2048 bytes */ /* Add an entry to dnode and don't care if it grows over 2048 bytes */
struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d, unsigned char *name, struct hpfs_dirent *hpfs_add_de(struct super_block *s, struct dnode *d,
const unsigned char *name,
unsigned namelen, secno down_ptr) unsigned namelen, secno down_ptr)
{ {
struct hpfs_dirent *de; struct hpfs_dirent *de;
@ -223,7 +224,7 @@ static void fix_up_ptrs(struct super_block *s, struct dnode *d)
/* Add an entry to dnode and do dnode splitting if required */ /* Add an entry to dnode and do dnode splitting if required */
static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno, static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
unsigned char *name, unsigned namelen, const unsigned char *name, unsigned namelen,
struct hpfs_dirent *new_de, dnode_secno down_ptr) struct hpfs_dirent *new_de, dnode_secno down_ptr)
{ {
struct quad_buffer_head qbh, qbh1, qbh2; struct quad_buffer_head qbh, qbh1, qbh2;
@ -231,7 +232,7 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
dnode_secno adno, rdno; dnode_secno adno, rdno;
struct hpfs_dirent *de; struct hpfs_dirent *de;
struct hpfs_dirent nde; struct hpfs_dirent nde;
char *nname; unsigned char *nname;
int h; int h;
int pos; int pos;
struct buffer_head *bh; struct buffer_head *bh;
@ -305,7 +306,9 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
pos++; pos++;
} }
copy_de(new_de = &nde, de); copy_de(new_de = &nde, de);
memcpy(name = nname, de->name, namelen = de->namelen); memcpy(nname, de->name, de->namelen);
name = nname;
namelen = de->namelen;
for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4); for_all_poss(i, hpfs_pos_subst, ((loff_t)dno << 4) | pos, 4);
down_ptr = adno; down_ptr = adno;
set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0); set_last_pointer(i->i_sb, ad, de->down ? de_down_pointer(de) : 0);
@ -368,7 +371,8 @@ static int hpfs_add_to_dnode(struct inode *i, dnode_secno dno,
* I hope, now it's finally bug-free. * I hope, now it's finally bug-free.
*/ */
int hpfs_add_dirent(struct inode *i, unsigned char *name, unsigned namelen, int hpfs_add_dirent(struct inode *i,
const unsigned char *name, unsigned namelen,
struct hpfs_dirent *new_de, int cdepth) struct hpfs_dirent *new_de, int cdepth)
{ {
struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
@ -897,7 +901,8 @@ struct hpfs_dirent *map_pos_dirent(struct inode *inode, loff_t *posp,
/* Find a dirent in tree */ /* Find a dirent in tree */
struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, char *name, unsigned len, struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno,
const unsigned char *name, unsigned len,
dnode_secno *dd, struct quad_buffer_head *qbh) dnode_secno *dd, struct quad_buffer_head *qbh)
{ {
struct dnode *dnode; struct dnode *dnode;
@ -988,8 +993,8 @@ void hpfs_remove_dtree(struct super_block *s, dnode_secno dno)
struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno, struct hpfs_dirent *map_fnode_dirent(struct super_block *s, fnode_secno fno,
struct fnode *f, struct quad_buffer_head *qbh) struct fnode *f, struct quad_buffer_head *qbh)
{ {
char *name1; unsigned char *name1;
char *name2; unsigned char *name2;
int name1len, name2len; int name1len, name2len;
struct dnode *d; struct dnode *d;
dnode_secno dno, downd; dnode_secno dno, downd;

View file

@ -62,8 +62,8 @@ static char *get_indirect_ea(struct super_block *s, int ano, secno a, int size)
return ret; return ret;
} }
static void set_indirect_ea(struct super_block *s, int ano, secno a, char *data, static void set_indirect_ea(struct super_block *s, int ano, secno a,
int size) const char *data, int size)
{ {
hpfs_ea_write(s, a, ano, 0, size, data); hpfs_ea_write(s, a, ano, 0, size, data);
} }
@ -186,7 +186,8 @@ char *hpfs_get_ea(struct super_block *s, struct fnode *fnode, char *key, int *si
* This driver can't change sizes of eas ('cause I just don't need it). * This driver can't change sizes of eas ('cause I just don't need it).
*/ */
void hpfs_set_ea(struct inode *inode, struct fnode *fnode, char *key, char *data, int size) void hpfs_set_ea(struct inode *inode, struct fnode *fnode, const char *key,
const char *data, int size)
{ {
fnode_secno fno = inode->i_ino; fnode_secno fno = inode->i_ino;
struct super_block *s = inode->i_sb; struct super_block *s = inode->i_sb;

View file

@ -215,7 +215,7 @@ secno hpfs_bplus_lookup(struct super_block *, struct inode *, struct bplus_heade
secno hpfs_add_sector_to_btree(struct super_block *, secno, int, unsigned); secno hpfs_add_sector_to_btree(struct super_block *, secno, int, unsigned);
void hpfs_remove_btree(struct super_block *, struct bplus_header *); void hpfs_remove_btree(struct super_block *, struct bplus_header *);
int hpfs_ea_read(struct super_block *, secno, int, unsigned, unsigned, char *); int hpfs_ea_read(struct super_block *, secno, int, unsigned, unsigned, char *);
int hpfs_ea_write(struct super_block *, secno, int, unsigned, unsigned, char *); int hpfs_ea_write(struct super_block *, secno, int, unsigned, unsigned, const char *);
void hpfs_ea_remove(struct super_block *, secno, int, unsigned); void hpfs_ea_remove(struct super_block *, secno, int, unsigned);
void hpfs_truncate_btree(struct super_block *, secno, int, unsigned); void hpfs_truncate_btree(struct super_block *, secno, int, unsigned);
void hpfs_remove_fnode(struct super_block *, fnode_secno fno); void hpfs_remove_fnode(struct super_block *, fnode_secno fno);
@ -244,13 +244,17 @@ extern const struct file_operations hpfs_dir_ops;
void hpfs_add_pos(struct inode *, loff_t *); void hpfs_add_pos(struct inode *, loff_t *);
void hpfs_del_pos(struct inode *, loff_t *); void hpfs_del_pos(struct inode *, loff_t *);
struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *, unsigned char *, unsigned, secno); struct hpfs_dirent *hpfs_add_de(struct super_block *, struct dnode *,
int hpfs_add_dirent(struct inode *, unsigned char *, unsigned, struct hpfs_dirent *, int); const unsigned char *, unsigned, secno);
int hpfs_add_dirent(struct inode *, const unsigned char *, unsigned,
struct hpfs_dirent *, int);
int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int); int hpfs_remove_dirent(struct inode *, dnode_secno, struct hpfs_dirent *, struct quad_buffer_head *, int);
void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *); void hpfs_count_dnodes(struct super_block *, dnode_secno, int *, int *, int *);
dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno); dnode_secno hpfs_de_as_down_as_possible(struct super_block *, dnode_secno dno);
struct hpfs_dirent *map_pos_dirent(struct inode *, loff_t *, struct quad_buffer_head *); struct hpfs_dirent *map_pos_dirent(struct inode *, loff_t *, struct quad_buffer_head *);
struct hpfs_dirent *map_dirent(struct inode *, dnode_secno, char *, unsigned, dnode_secno *, struct quad_buffer_head *); struct hpfs_dirent *map_dirent(struct inode *, dnode_secno,
const unsigned char *, unsigned, dnode_secno *,
struct quad_buffer_head *);
void hpfs_remove_dtree(struct super_block *, dnode_secno); void hpfs_remove_dtree(struct super_block *, dnode_secno);
struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct fnode *, struct quad_buffer_head *); struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct fnode *, struct quad_buffer_head *);
@ -259,7 +263,8 @@ struct hpfs_dirent *map_fnode_dirent(struct super_block *, fnode_secno, struct f
void hpfs_ea_ext_remove(struct super_block *, secno, int, unsigned); void hpfs_ea_ext_remove(struct super_block *, secno, int, unsigned);
int hpfs_read_ea(struct super_block *, struct fnode *, char *, char *, int); int hpfs_read_ea(struct super_block *, struct fnode *, char *, char *, int);
char *hpfs_get_ea(struct super_block *, struct fnode *, char *, int *); char *hpfs_get_ea(struct super_block *, struct fnode *, char *, int *);
void hpfs_set_ea(struct inode *, struct fnode *, char *, char *, int); void hpfs_set_ea(struct inode *, struct fnode *, const char *,
const char *, int);
/* file.c */ /* file.c */
@ -282,7 +287,7 @@ void hpfs_delete_inode(struct inode *);
unsigned *hpfs_map_dnode_bitmap(struct super_block *, struct quad_buffer_head *); unsigned *hpfs_map_dnode_bitmap(struct super_block *, struct quad_buffer_head *);
unsigned *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head *, char *); unsigned *hpfs_map_bitmap(struct super_block *, unsigned, struct quad_buffer_head *, char *);
char *hpfs_load_code_page(struct super_block *, secno); unsigned char *hpfs_load_code_page(struct super_block *, secno);
secno *hpfs_load_bitmap_directory(struct super_block *, secno bmp); secno *hpfs_load_bitmap_directory(struct super_block *, secno bmp);
struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **); struct fnode *hpfs_map_fnode(struct super_block *s, ino_t, struct buffer_head **);
struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **); struct anode *hpfs_map_anode(struct super_block *s, anode_secno, struct buffer_head **);
@ -292,12 +297,13 @@ dnode_secno hpfs_fnode_dno(struct super_block *s, ino_t ino);
/* name.c */ /* name.c */
unsigned char hpfs_upcase(unsigned char *, unsigned char); unsigned char hpfs_upcase(unsigned char *, unsigned char);
int hpfs_chk_name(unsigned char *, unsigned *); int hpfs_chk_name(const unsigned char *, unsigned *);
char *hpfs_translate_name(struct super_block *, unsigned char *, unsigned, int, int); unsigned char *hpfs_translate_name(struct super_block *, unsigned char *, unsigned, int, int);
int hpfs_compare_names(struct super_block *, unsigned char *, unsigned, unsigned char *, unsigned, int); int hpfs_compare_names(struct super_block *, const unsigned char *, unsigned,
int hpfs_is_name_long(unsigned char *, unsigned); const unsigned char *, unsigned, int);
void hpfs_adjust_length(unsigned char *, unsigned *); int hpfs_is_name_long(const unsigned char *, unsigned);
void hpfs_decide_conv(struct inode *, unsigned char *, unsigned); void hpfs_adjust_length(const unsigned char *, unsigned *);
void hpfs_decide_conv(struct inode *, const unsigned char *, unsigned);
/* namei.c */ /* namei.c */

View file

@ -46,7 +46,7 @@ void hpfs_read_inode(struct inode *i)
struct fnode *fnode; struct fnode *fnode;
struct super_block *sb = i->i_sb; struct super_block *sb = i->i_sb;
struct hpfs_inode_info *hpfs_inode = hpfs_i(i); struct hpfs_inode_info *hpfs_inode = hpfs_i(i);
unsigned char *ea; void *ea;
int ea_size; int ea_size;
if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) { if (!(fnode = hpfs_map_fnode(sb, i->i_ino, &bh))) {
@ -112,7 +112,7 @@ void hpfs_read_inode(struct inode *i)
} }
} }
if (fnode->dirflag) { if (fnode->dirflag) {
unsigned n_dnodes, n_subdirs; int n_dnodes, n_subdirs;
i->i_mode |= S_IFDIR; i->i_mode |= S_IFDIR;
i->i_op = &hpfs_dir_iops; i->i_op = &hpfs_dir_iops;
i->i_fop = &hpfs_dir_ops; i->i_fop = &hpfs_dir_ops;

View file

@ -35,7 +35,7 @@ unsigned int *hpfs_map_bitmap(struct super_block *s, unsigned bmp_block,
* lowercasing table * lowercasing table
*/ */
char *hpfs_load_code_page(struct super_block *s, secno cps) unsigned char *hpfs_load_code_page(struct super_block *s, secno cps)
{ {
struct buffer_head *bh; struct buffer_head *bh;
secno cpds; secno cpds;
@ -71,7 +71,7 @@ char *hpfs_load_code_page(struct super_block *s, secno cps)
brelse(bh); brelse(bh);
return NULL; return NULL;
} }
ptr = (char *)cpd + cpd->offs[cpi] + 6; ptr = (unsigned char *)cpd + cpd->offs[cpi] + 6;
if (!(cp_table = kmalloc(256, GFP_KERNEL))) { if (!(cp_table = kmalloc(256, GFP_KERNEL))) {
printk("HPFS: out of memory for code page table\n"); printk("HPFS: out of memory for code page table\n");
brelse(bh); brelse(bh);
@ -217,7 +217,7 @@ struct dnode *hpfs_map_dnode(struct super_block *s, unsigned secno,
if ((dnode = hpfs_map_4sectors(s, secno, qbh, DNODE_RD_AHEAD))) if ((dnode = hpfs_map_4sectors(s, secno, qbh, DNODE_RD_AHEAD)))
if (hpfs_sb(s)->sb_chk) { if (hpfs_sb(s)->sb_chk) {
unsigned p, pp = 0; unsigned p, pp = 0;
unsigned char *d = (char *)dnode; unsigned char *d = (unsigned char *)dnode;
int b = 0; int b = 0;
if (dnode->magic != DNODE_MAGIC) { if (dnode->magic != DNODE_MAGIC) {
hpfs_error(s, "bad magic on dnode %08x", secno); hpfs_error(s, "bad magic on dnode %08x", secno);

View file

@ -8,16 +8,16 @@
#include "hpfs_fn.h" #include "hpfs_fn.h"
static char *text_postfix[]={ static const char *text_postfix[]={
".ASM", ".BAS", ".BAT", ".C", ".CC", ".CFG", ".CMD", ".CON", ".CPP", ".DEF", ".ASM", ".BAS", ".BAT", ".C", ".CC", ".CFG", ".CMD", ".CON", ".CPP", ".DEF",
".DOC", ".DPR", ".ERX", ".H", ".HPP", ".HTM", ".HTML", ".JAVA", ".LOG", ".PAS", ".DOC", ".DPR", ".ERX", ".H", ".HPP", ".HTM", ".HTML", ".JAVA", ".LOG", ".PAS",
".RC", ".TEX", ".TXT", ".Y", ""}; ".RC", ".TEX", ".TXT", ".Y", ""};
static char *text_prefix[]={ static const char *text_prefix[]={
"AUTOEXEC.", "CHANGES", "COPYING", "CONFIG.", "CREDITS", "FAQ", "FILE_ID.DIZ", "AUTOEXEC.", "CHANGES", "COPYING", "CONFIG.", "CREDITS", "FAQ", "FILE_ID.DIZ",
"MAKEFILE", "READ.ME", "README", "TERMCAP", ""}; "MAKEFILE", "READ.ME", "README", "TERMCAP", ""};
void hpfs_decide_conv(struct inode *inode, unsigned char *name, unsigned len) void hpfs_decide_conv(struct inode *inode, const unsigned char *name, unsigned len)
{ {
struct hpfs_inode_info *hpfs_inode = hpfs_i(inode); struct hpfs_inode_info *hpfs_inode = hpfs_i(inode);
int i; int i;
@ -71,7 +71,7 @@ static inline unsigned char locase(unsigned char *dir, unsigned char a)
return dir[a]; return dir[a];
} }
int hpfs_chk_name(unsigned char *name, unsigned *len) int hpfs_chk_name(const unsigned char *name, unsigned *len)
{ {
int i; int i;
if (*len > 254) return -ENAMETOOLONG; if (*len > 254) return -ENAMETOOLONG;
@ -83,10 +83,10 @@ int hpfs_chk_name(unsigned char *name, unsigned *len)
return 0; return 0;
} }
char *hpfs_translate_name(struct super_block *s, unsigned char *from, unsigned char *hpfs_translate_name(struct super_block *s, unsigned char *from,
unsigned len, int lc, int lng) unsigned len, int lc, int lng)
{ {
char *to; unsigned char *to;
int i; int i;
if (hpfs_sb(s)->sb_chk >= 2) if (hpfs_is_name_long(from, len) != lng) { if (hpfs_sb(s)->sb_chk >= 2) if (hpfs_is_name_long(from, len) != lng) {
printk("HPFS: Long name flag mismatch - name "); printk("HPFS: Long name flag mismatch - name ");
@ -103,8 +103,9 @@ char *hpfs_translate_name(struct super_block *s, unsigned char *from,
return to; return to;
} }
int hpfs_compare_names(struct super_block *s, unsigned char *n1, unsigned l1, int hpfs_compare_names(struct super_block *s,
unsigned char *n2, unsigned l2, int last) const unsigned char *n1, unsigned l1,
const unsigned char *n2, unsigned l2, int last)
{ {
unsigned l = l1 < l2 ? l1 : l2; unsigned l = l1 < l2 ? l1 : l2;
unsigned i; unsigned i;
@ -120,7 +121,7 @@ int hpfs_compare_names(struct super_block *s, unsigned char *n1, unsigned l1,
return 0; return 0;
} }
int hpfs_is_name_long(unsigned char *name, unsigned len) int hpfs_is_name_long(const unsigned char *name, unsigned len)
{ {
int i,j; int i,j;
for (i = 0; i < len && name[i] != '.'; i++) for (i = 0; i < len && name[i] != '.'; i++)
@ -134,7 +135,7 @@ int hpfs_is_name_long(unsigned char *name, unsigned len)
/* OS/2 clears dots and spaces at the end of file name, so we have to */ /* OS/2 clears dots and spaces at the end of file name, so we have to */
void hpfs_adjust_length(unsigned char *name, unsigned *len) void hpfs_adjust_length(const unsigned char *name, unsigned *len)
{ {
if (!*len) return; if (!*len) return;
if (*len == 1 && name[0] == '.') return; if (*len == 1 && name[0] == '.') return;

View file

@ -11,7 +11,7 @@
static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct quad_buffer_head qbh0; struct quad_buffer_head qbh0;
struct buffer_head *bh; struct buffer_head *bh;
@ -24,7 +24,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
int r; int r;
struct hpfs_dirent dee; struct hpfs_dirent dee;
int err; int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
lock_kernel(); lock_kernel();
err = -ENOSPC; err = -ENOSPC;
fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh); fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
@ -62,7 +62,7 @@ static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
result->i_mode &= ~0222; result->i_mode &= ~0222;
mutex_lock(&hpfs_i(dir)->i_mutex); mutex_lock(&hpfs_i(dir)->i_mutex);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail3; goto bail3;
if (r == -1) { if (r == -1) {
@ -121,7 +121,7 @@ bail:
static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd) static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struct nameidata *nd)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct inode *result = NULL; struct inode *result = NULL;
struct buffer_head *bh; struct buffer_head *bh;
@ -130,7 +130,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
int r; int r;
struct hpfs_dirent dee; struct hpfs_dirent dee;
int err; int err;
if ((err = hpfs_chk_name((char *)name, &len))) if ((err = hpfs_chk_name(name, &len)))
return err==-ENOENT ? -EINVAL : err; return err==-ENOENT ? -EINVAL : err;
lock_kernel(); lock_kernel();
err = -ENOSPC; err = -ENOSPC;
@ -155,7 +155,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
result->i_op = &hpfs_file_iops; result->i_op = &hpfs_file_iops;
result->i_fop = &hpfs_file_ops; result->i_fop = &hpfs_file_ops;
result->i_nlink = 1; result->i_nlink = 1;
hpfs_decide_conv(result, (char *)name, len); hpfs_decide_conv(result, name, len);
hpfs_i(result)->i_parent_dir = dir->i_ino; hpfs_i(result)->i_parent_dir = dir->i_ino;
result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date); result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, dee.creation_date);
result->i_ctime.tv_nsec = 0; result->i_ctime.tv_nsec = 0;
@ -170,7 +170,7 @@ static int hpfs_create(struct inode *dir, struct dentry *dentry, int mode, struc
hpfs_i(result)->mmu_private = 0; hpfs_i(result)->mmu_private = 0;
mutex_lock(&hpfs_i(dir)->i_mutex); mutex_lock(&hpfs_i(dir)->i_mutex);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail2; goto bail2;
if (r == -1) { if (r == -1) {
@ -211,7 +211,7 @@ bail:
static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev) static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t rdev)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct buffer_head *bh; struct buffer_head *bh;
struct fnode *fnode; struct fnode *fnode;
@ -220,7 +220,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
struct hpfs_dirent dee; struct hpfs_dirent dee;
struct inode *result = NULL; struct inode *result = NULL;
int err; int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM; if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM;
if (!new_valid_dev(rdev)) if (!new_valid_dev(rdev))
return -EINVAL; return -EINVAL;
@ -256,7 +256,7 @@ static int hpfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t
init_special_inode(result, mode, rdev); init_special_inode(result, mode, rdev);
mutex_lock(&hpfs_i(dir)->i_mutex); mutex_lock(&hpfs_i(dir)->i_mutex);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail2; goto bail2;
if (r == -1) { if (r == -1) {
@ -289,7 +289,7 @@ bail:
static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink) static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct buffer_head *bh; struct buffer_head *bh;
struct fnode *fnode; struct fnode *fnode;
@ -298,7 +298,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
struct hpfs_dirent dee; struct hpfs_dirent dee;
struct inode *result; struct inode *result;
int err; int err;
if ((err = hpfs_chk_name((char *)name, &len))) return err==-ENOENT ? -EINVAL : err; if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
lock_kernel(); lock_kernel();
if (hpfs_sb(dir->i_sb)->sb_eas < 2) { if (hpfs_sb(dir->i_sb)->sb_eas < 2) {
unlock_kernel(); unlock_kernel();
@ -335,7 +335,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
result->i_data.a_ops = &hpfs_symlink_aops; result->i_data.a_ops = &hpfs_symlink_aops;
mutex_lock(&hpfs_i(dir)->i_mutex); mutex_lock(&hpfs_i(dir)->i_mutex);
r = hpfs_add_dirent(dir, (char *)name, len, &dee, 0); r = hpfs_add_dirent(dir, name, len, &dee, 0);
if (r == 1) if (r == 1)
goto bail2; goto bail2;
if (r == -1) { if (r == -1) {
@ -345,7 +345,7 @@ static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *sy
fnode->len = len; fnode->len = len;
memcpy(fnode->name, name, len > 15 ? 15 : len); memcpy(fnode->name, name, len > 15 ? 15 : len);
fnode->up = dir->i_ino; fnode->up = dir->i_ino;
hpfs_set_ea(result, fnode, "SYMLINK", (char *)symlink, strlen(symlink)); hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink));
mark_buffer_dirty(bh); mark_buffer_dirty(bh);
brelse(bh); brelse(bh);
@ -369,7 +369,7 @@ bail:
static int hpfs_unlink(struct inode *dir, struct dentry *dentry) static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
struct hpfs_dirent *de; struct hpfs_dirent *de;
@ -381,12 +381,12 @@ static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
int err; int err;
lock_kernel(); lock_kernel();
hpfs_adjust_length((char *)name, &len); hpfs_adjust_length(name, &len);
again: again:
mutex_lock(&hpfs_i(inode)->i_parent_mutex); mutex_lock(&hpfs_i(inode)->i_parent_mutex);
mutex_lock(&hpfs_i(dir)->i_mutex); mutex_lock(&hpfs_i(dir)->i_mutex);
err = -ENOENT; err = -ENOENT;
de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
if (!de) if (!de)
goto out; goto out;
@ -413,22 +413,25 @@ again:
mutex_unlock(&hpfs_i(dir)->i_mutex); mutex_unlock(&hpfs_i(dir)->i_mutex);
mutex_unlock(&hpfs_i(inode)->i_parent_mutex); mutex_unlock(&hpfs_i(inode)->i_parent_mutex);
d_drop(dentry); dentry_unhash(dentry);
spin_lock(&dentry->d_lock); if (!d_unhashed(dentry)) {
if (atomic_read(&dentry->d_count) > 1 || dput(dentry);
generic_permission(inode, MAY_WRITE, NULL) || unlock_kernel();
return -ENOSPC;
}
if (generic_permission(inode, MAY_WRITE, NULL) ||
!S_ISREG(inode->i_mode) || !S_ISREG(inode->i_mode) ||
get_write_access(inode)) { get_write_access(inode)) {
spin_unlock(&dentry->d_lock);
d_rehash(dentry); d_rehash(dentry);
dput(dentry);
} else { } else {
struct iattr newattrs; struct iattr newattrs;
spin_unlock(&dentry->d_lock);
/*printk("HPFS: truncating file before delete.\n");*/ /*printk("HPFS: truncating file before delete.\n");*/
newattrs.ia_size = 0; newattrs.ia_size = 0;
newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
err = notify_change(dentry, &newattrs); err = notify_change(dentry, &newattrs);
put_write_access(inode); put_write_access(inode);
dput(dentry);
if (!err) if (!err)
goto again; goto again;
} }
@ -451,7 +454,7 @@ out:
static int hpfs_rmdir(struct inode *dir, struct dentry *dentry) static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
unsigned len = dentry->d_name.len; unsigned len = dentry->d_name.len;
struct quad_buffer_head qbh; struct quad_buffer_head qbh;
struct hpfs_dirent *de; struct hpfs_dirent *de;
@ -462,12 +465,12 @@ static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
int err; int err;
int r; int r;
hpfs_adjust_length((char *)name, &len); hpfs_adjust_length(name, &len);
lock_kernel(); lock_kernel();
mutex_lock(&hpfs_i(inode)->i_parent_mutex); mutex_lock(&hpfs_i(inode)->i_parent_mutex);
mutex_lock(&hpfs_i(dir)->i_mutex); mutex_lock(&hpfs_i(dir)->i_mutex);
err = -ENOENT; err = -ENOENT;
de = map_dirent(dir, hpfs_i(dir)->i_dno, (char *)name, len, &dno, &qbh); de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
if (!de) if (!de)
goto out; goto out;
@ -546,10 +549,10 @@ const struct address_space_operations hpfs_symlink_aops = {
static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry, static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct inode *new_dir, struct dentry *new_dentry) struct inode *new_dir, struct dentry *new_dentry)
{ {
char *old_name = (char *)old_dentry->d_name.name; const unsigned char *old_name = old_dentry->d_name.name;
int old_len = old_dentry->d_name.len; unsigned old_len = old_dentry->d_name.len;
char *new_name = (char *)new_dentry->d_name.name; const unsigned char *new_name = new_dentry->d_name.name;
int new_len = new_dentry->d_name.len; unsigned new_len = new_dentry->d_name.len;
struct inode *i = old_dentry->d_inode; struct inode *i = old_dentry->d_inode;
struct inode *new_inode = new_dentry->d_inode; struct inode *new_inode = new_dentry->d_inode;
struct quad_buffer_head qbh, qbh1; struct quad_buffer_head qbh, qbh1;
@ -560,9 +563,9 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
struct buffer_head *bh; struct buffer_head *bh;
struct fnode *fnode; struct fnode *fnode;
int err; int err;
if ((err = hpfs_chk_name((char *)new_name, &new_len))) return err; if ((err = hpfs_chk_name(new_name, &new_len))) return err;
err = 0; err = 0;
hpfs_adjust_length((char *)old_name, &old_len); hpfs_adjust_length(old_name, &old_len);
lock_kernel(); lock_kernel();
/* order doesn't matter, due to VFS exclusion */ /* order doesn't matter, due to VFS exclusion */
@ -579,7 +582,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto end1; goto end1;
} }
if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
hpfs_error(i->i_sb, "lookup succeeded but map dirent failed"); hpfs_error(i->i_sb, "lookup succeeded but map dirent failed");
err = -ENOENT; err = -ENOENT;
goto end1; goto end1;
@ -590,7 +593,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
if (new_inode) { if (new_inode) {
int r; int r;
if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) { if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, (char *)new_name, new_len, NULL, &qbh1))) { if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) {
clear_nlink(new_inode); clear_nlink(new_inode);
copy_de(nde, &de); copy_de(nde, &de);
memcpy(nde->name, new_name, new_len); memcpy(nde->name, new_name, new_len);
@ -618,7 +621,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
} }
if (new_dir == old_dir) if (new_dir == old_dir)
if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, (char *)old_name, old_len, &dno, &qbh))) { if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
hpfs_unlock_creation(i->i_sb); hpfs_unlock_creation(i->i_sb);
hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2"); hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
err = -ENOENT; err = -ENOENT;
@ -648,7 +651,7 @@ static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
brelse(bh); brelse(bh);
} }
hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv; hpfs_i(i)->i_conv = hpfs_sb(i->i_sb)->sb_conv;
hpfs_decide_conv(i, (char *)new_name, new_len); hpfs_decide_conv(i, new_name, new_len);
end1: end1:
if (old_dir != new_dir) if (old_dir != new_dir)
mutex_unlock(&hpfs_i(new_dir)->i_mutex); mutex_unlock(&hpfs_i(new_dir)->i_mutex);

View file

@ -718,7 +718,7 @@ static int hppfs_fill_super(struct super_block *sb, void *d, int silent)
struct vfsmount *proc_mnt; struct vfsmount *proc_mnt;
int err = -ENOENT; int err = -ENOENT;
proc_mnt = do_kern_mount("proc", 0, "proc", NULL); proc_mnt = mntget(current->nsproxy->pid_ns->proc_mnt);
if (IS_ERR(proc_mnt)) if (IS_ERR(proc_mnt))
goto out; goto out;

View file

@ -70,6 +70,8 @@ extern struct vfsmount *copy_tree(struct vfsmount *, struct dentry *, int);
extern void __init mnt_init(void); extern void __init mnt_init(void);
extern spinlock_t vfsmount_lock;
/* /*
* fs_struct.c * fs_struct.c
*/ */

View file

@ -338,28 +338,14 @@ int simple_readpage(struct file *file, struct page *page)
return 0; return 0;
} }
int simple_prepare_write(struct file *file, struct page *page,
unsigned from, unsigned to)
{
if (!PageUptodate(page)) {
if (to - from != PAGE_CACHE_SIZE)
zero_user_segments(page,
0, from,
to, PAGE_CACHE_SIZE);
}
return 0;
}
int simple_write_begin(struct file *file, struct address_space *mapping, int simple_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata) struct page **pagep, void **fsdata)
{ {
struct page *page; struct page *page;
pgoff_t index; pgoff_t index;
unsigned from;
index = pos >> PAGE_CACHE_SHIFT; index = pos >> PAGE_CACHE_SHIFT;
from = pos & (PAGE_CACHE_SIZE - 1);
page = grab_cache_page_write_begin(mapping, index, flags); page = grab_cache_page_write_begin(mapping, index, flags);
if (!page) if (!page)
@ -367,14 +353,48 @@ int simple_write_begin(struct file *file, struct address_space *mapping,
*pagep = page; *pagep = page;
return simple_prepare_write(file, page, from, from+len); if (!PageUptodate(page) && (len != PAGE_CACHE_SIZE)) {
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
zero_user_segments(page, 0, from, from + len, PAGE_CACHE_SIZE);
}
return 0;
} }
static int simple_commit_write(struct file *file, struct page *page, /**
unsigned from, unsigned to) * simple_write_end - .write_end helper for non-block-device FSes
* @available: See .write_end of address_space_operations
* @file: "
* @mapping: "
* @pos: "
* @len: "
* @copied: "
* @page: "
* @fsdata: "
*
* simple_write_end does the minimum needed for updating a page after writing is
* done. It has the same API signature as the .write_end of
* address_space_operations vector. So it can just be set onto .write_end for
* FSes that don't need any other processing. i_mutex is assumed to be held.
* Block based filesystems should use generic_write_end().
* NOTE: Even though i_size might get updated by this function, mark_inode_dirty
* is not called, so a filesystem that actually does store data in .write_inode
* should extend on what's done here with a call to mark_inode_dirty() in the
* case that i_size has changed.
*/
int simple_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to; loff_t last_pos = pos + copied;
/* zero the stale part of the page if we did a short copy */
if (copied < len) {
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
zero_user(page, from + copied, len - copied);
}
if (!PageUptodate(page)) if (!PageUptodate(page))
SetPageUptodate(page); SetPageUptodate(page);
@ -382,28 +402,10 @@ static int simple_commit_write(struct file *file, struct page *page,
* No need to use i_size_read() here, the i_size * No need to use i_size_read() here, the i_size
* cannot change under us because we hold the i_mutex. * cannot change under us because we hold the i_mutex.
*/ */
if (pos > inode->i_size) if (last_pos > inode->i_size)
i_size_write(inode, pos); i_size_write(inode, last_pos);
set_page_dirty(page); set_page_dirty(page);
return 0;
}
int simple_write_end(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned copied,
struct page *page, void *fsdata)
{
unsigned from = pos & (PAGE_CACHE_SIZE - 1);
/* zero the stale part of the page if we did a short copy */
if (copied < len) {
void *kaddr = kmap_atomic(page, KM_USER0);
memset(kaddr + from + copied, 0, len - copied);
flush_dcache_page(page);
kunmap_atomic(kaddr, KM_USER0);
}
simple_commit_write(file, page, from, from+copied);
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
@ -853,7 +855,6 @@ EXPORT_SYMBOL(simple_getattr);
EXPORT_SYMBOL(simple_link); EXPORT_SYMBOL(simple_link);
EXPORT_SYMBOL(simple_lookup); EXPORT_SYMBOL(simple_lookup);
EXPORT_SYMBOL(simple_pin_fs); EXPORT_SYMBOL(simple_pin_fs);
EXPORT_UNUSED_SYMBOL(simple_prepare_write);
EXPORT_SYMBOL(simple_readpage); EXPORT_SYMBOL(simple_readpage);
EXPORT_SYMBOL(simple_release_fs); EXPORT_SYMBOL(simple_release_fs);
EXPORT_SYMBOL(simple_rename); EXPORT_SYMBOL(simple_rename);

View file

@ -1182,8 +1182,9 @@ int __break_lease(struct inode *inode, unsigned int mode)
struct file_lock *fl; struct file_lock *fl;
unsigned long break_time; unsigned long break_time;
int i_have_this_lease = 0; int i_have_this_lease = 0;
int want_write = (mode & O_ACCMODE) != O_RDONLY;
new_fl = lease_alloc(NULL, mode & FMODE_WRITE ? F_WRLCK : F_RDLCK); new_fl = lease_alloc(NULL, want_write ? F_WRLCK : F_RDLCK);
lock_kernel(); lock_kernel();
@ -1197,7 +1198,7 @@ int __break_lease(struct inode *inode, unsigned int mode)
if (fl->fl_owner == current->files) if (fl->fl_owner == current->files)
i_have_this_lease = 1; i_have_this_lease = 1;
if (mode & FMODE_WRITE) { if (want_write) {
/* If we want write access, we have to revoke any lease. */ /* If we want write access, we have to revoke any lease. */
future = F_UNLCK | F_INPROGRESS; future = F_UNLCK | F_INPROGRESS;
} else if (flock->fl_type & F_INPROGRESS) { } else if (flock->fl_type & F_INPROGRESS) {

View file

@ -689,33 +689,20 @@ static __always_inline void follow_dotdot(struct nameidata *nd)
set_root(nd); set_root(nd);
while(1) { while(1) {
struct vfsmount *parent;
struct dentry *old = nd->path.dentry; struct dentry *old = nd->path.dentry;
if (nd->path.dentry == nd->root.dentry && if (nd->path.dentry == nd->root.dentry &&
nd->path.mnt == nd->root.mnt) { nd->path.mnt == nd->root.mnt) {
break; break;
} }
spin_lock(&dcache_lock);
if (nd->path.dentry != nd->path.mnt->mnt_root) { if (nd->path.dentry != nd->path.mnt->mnt_root) {
nd->path.dentry = dget(nd->path.dentry->d_parent); /* rare case of legitimate dget_parent()... */
spin_unlock(&dcache_lock); nd->path.dentry = dget_parent(nd->path.dentry);
dput(old); dput(old);
break; break;
} }
spin_unlock(&dcache_lock); if (!follow_up(&nd->path))
spin_lock(&vfsmount_lock);
parent = nd->path.mnt->mnt_parent;
if (parent == nd->path.mnt) {
spin_unlock(&vfsmount_lock);
break; break;
}
mntget(parent);
nd->path.dentry = dget(nd->path.mnt->mnt_mountpoint);
spin_unlock(&vfsmount_lock);
dput(old);
mntput(nd->path.mnt);
nd->path.mnt = parent;
} }
follow_mount(&nd->path); follow_mount(&nd->path);
} }
@ -1347,7 +1334,7 @@ static int may_delete(struct inode *dir,struct dentry *victim,int isdir)
return -ENOENT; return -ENOENT;
BUG_ON(victim->d_parent->d_inode != dir); BUG_ON(victim->d_parent->d_inode != dir);
audit_inode_child(victim->d_name.name, victim, dir); audit_inode_child(victim, dir);
error = inode_permission(dir, MAY_WRITE | MAY_EXEC); error = inode_permission(dir, MAY_WRITE | MAY_EXEC);
if (error) if (error)
@ -1503,7 +1490,7 @@ int may_open(struct path *path, int acc_mode, int flag)
* An append-only file must be opened in append mode for writing. * An append-only file must be opened in append mode for writing.
*/ */
if (IS_APPEND(inode)) { if (IS_APPEND(inode)) {
if ((flag & FMODE_WRITE) && !(flag & O_APPEND)) if ((flag & O_ACCMODE) != O_RDONLY && !(flag & O_APPEND))
return -EPERM; return -EPERM;
if (flag & O_TRUNC) if (flag & O_TRUNC)
return -EPERM; return -EPERM;
@ -1547,7 +1534,7 @@ static int handle_truncate(struct path *path)
* what get passed to sys_open(). * what get passed to sys_open().
*/ */
static int __open_namei_create(struct nameidata *nd, struct path *path, static int __open_namei_create(struct nameidata *nd, struct path *path,
int flag, int mode) int open_flag, int mode)
{ {
int error; int error;
struct dentry *dir = nd->path.dentry; struct dentry *dir = nd->path.dentry;
@ -1565,7 +1552,7 @@ out_unlock:
if (error) if (error)
return error; return error;
/* Don't check for write permission, don't truncate */ /* Don't check for write permission, don't truncate */
return may_open(&nd->path, 0, flag & ~O_TRUNC); return may_open(&nd->path, 0, open_flag & ~O_TRUNC);
} }
/* /*
@ -1736,7 +1723,7 @@ do_last:
error = mnt_want_write(nd.path.mnt); error = mnt_want_write(nd.path.mnt);
if (error) if (error)
goto exit_mutex_unlock; goto exit_mutex_unlock;
error = __open_namei_create(&nd, &path, flag, mode); error = __open_namei_create(&nd, &path, open_flag, mode);
if (error) { if (error) {
mnt_drop_write(nd.path.mnt); mnt_drop_write(nd.path.mnt);
goto exit; goto exit;
@ -1798,7 +1785,7 @@ ok:
if (error) if (error)
goto exit; goto exit;
} }
error = may_open(&nd.path, acc_mode, flag); error = may_open(&nd.path, acc_mode, open_flag);
if (error) { if (error) {
if (will_truncate) if (will_truncate)
mnt_drop_write(nd.path.mnt); mnt_drop_write(nd.path.mnt);
@ -2275,8 +2262,11 @@ int vfs_unlink(struct inode *dir, struct dentry *dentry)
error = -EBUSY; error = -EBUSY;
else { else {
error = security_inode_unlink(dir, dentry); error = security_inode_unlink(dir, dentry);
if (!error) if (!error) {
error = dir->i_op->unlink(dir, dentry); error = dir->i_op->unlink(dir, dentry);
if (!error)
dentry->d_inode->i_flags |= S_DEAD;
}
} }
mutex_unlock(&dentry->d_inode->i_mutex); mutex_unlock(&dentry->d_inode->i_mutex);
@ -2629,6 +2619,8 @@ static int vfs_rename_other(struct inode *old_dir, struct dentry *old_dentry,
else else
error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry); error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
if (!error) { if (!error) {
if (target)
target->i_flags |= S_DEAD;
if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE)) if (!(old_dir->i_sb->s_type->fs_flags & FS_RENAME_DOES_D_MOVE))
d_move(old_dentry, new_dentry); d_move(old_dentry, new_dentry);
} }
@ -2671,11 +2663,9 @@ int vfs_rename(struct inode *old_dir, struct dentry *old_dentry,
error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry);
else else
error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry);
if (!error) { if (!error)
const char *new_name = old_dentry->d_name.name; fsnotify_move(old_dir, new_dir, old_name, is_dir,
fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir,
new_dentry->d_inode, old_dentry); new_dentry->d_inode, old_dentry);
}
fsnotify_oldname_free(old_name); fsnotify_oldname_free(old_name);
return error; return error;

View file

@ -573,7 +573,7 @@ static struct vfsmount *clone_mnt(struct vfsmount *old, struct dentry *root,
mnt->mnt_master = old; mnt->mnt_master = old;
CLEAR_MNT_SHARED(mnt); CLEAR_MNT_SHARED(mnt);
} else if (!(flag & CL_PRIVATE)) { } else if (!(flag & CL_PRIVATE)) {
if ((flag & CL_PROPAGATION) || IS_MNT_SHARED(old)) if ((flag & CL_MAKE_SHARED) || IS_MNT_SHARED(old))
list_add(&mnt->mnt_share, &old->mnt_share); list_add(&mnt->mnt_share, &old->mnt_share);
if (IS_MNT_SLAVE(old)) if (IS_MNT_SLAVE(old))
list_add(&mnt->mnt_slave, &old->mnt_slave); list_add(&mnt->mnt_slave, &old->mnt_slave);
@ -737,6 +737,21 @@ static void m_stop(struct seq_file *m, void *v)
up_read(&namespace_sem); up_read(&namespace_sem);
} }
int mnt_had_events(struct proc_mounts *p)
{
struct mnt_namespace *ns = p->ns;
int res = 0;
spin_lock(&vfsmount_lock);
if (p->event != ns->event) {
p->event = ns->event;
res = 1;
}
spin_unlock(&vfsmount_lock);
return res;
}
struct proc_fs_info { struct proc_fs_info {
int flag; int flag;
const char *str; const char *str;
@ -1121,8 +1136,15 @@ SYSCALL_DEFINE2(umount, char __user *, name, int, flags)
{ {
struct path path; struct path path;
int retval; int retval;
int lookup_flags = 0;
retval = user_path(name, &path); if (flags & ~(MNT_FORCE | MNT_DETACH | MNT_EXPIRE | UMOUNT_NOFOLLOW))
return -EINVAL;
if (!(flags & UMOUNT_NOFOLLOW))
lookup_flags |= LOOKUP_FOLLOW;
retval = user_path_at(AT_FDCWD, name, lookup_flags, &path);
if (retval) if (retval)
goto out; goto out;
retval = -EINVAL; retval = -EINVAL;
@ -1246,6 +1268,21 @@ void drop_collected_mounts(struct vfsmount *mnt)
release_mounts(&umount_list); release_mounts(&umount_list);
} }
int iterate_mounts(int (*f)(struct vfsmount *, void *), void *arg,
struct vfsmount *root)
{
struct vfsmount *mnt;
int res = f(root, arg);
if (res)
return res;
list_for_each_entry(mnt, &root->mnt_list, mnt_list) {
res = f(mnt, arg);
if (res)
return res;
}
return 0;
}
static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end) static void cleanup_group_ids(struct vfsmount *mnt, struct vfsmount *end)
{ {
struct vfsmount *p; struct vfsmount *p;
@ -1538,7 +1575,7 @@ static int do_remount(struct path *path, int flags, int mnt_flags,
err = do_remount_sb(sb, flags, data, 0); err = do_remount_sb(sb, flags, data, 0);
if (!err) { if (!err) {
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
mnt_flags |= path->mnt->mnt_flags & MNT_PNODE_MASK; mnt_flags |= path->mnt->mnt_flags & MNT_PROPAGATION_MASK;
path->mnt->mnt_flags = mnt_flags; path->mnt->mnt_flags = mnt_flags;
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
} }
@ -1671,7 +1708,7 @@ int do_add_mount(struct vfsmount *newmnt, struct path *path,
{ {
int err; int err;
mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD); mnt_flags &= ~(MNT_SHARED | MNT_WRITE_HOLD | MNT_INTERNAL);
down_write(&namespace_sem); down_write(&namespace_sem);
/* Something was mounted here while we slept */ /* Something was mounted here while we slept */
@ -2314,17 +2351,13 @@ void __init mnt_init(void)
void put_mnt_ns(struct mnt_namespace *ns) void put_mnt_ns(struct mnt_namespace *ns)
{ {
struct vfsmount *root;
LIST_HEAD(umount_list); LIST_HEAD(umount_list);
if (!atomic_dec_and_lock(&ns->count, &vfsmount_lock)) if (!atomic_dec_and_test(&ns->count))
return; return;
root = ns->root;
ns->root = NULL;
spin_unlock(&vfsmount_lock);
down_write(&namespace_sem); down_write(&namespace_sem);
spin_lock(&vfsmount_lock); spin_lock(&vfsmount_lock);
umount_tree(root, 0, &umount_list); umount_tree(ns->root, 0, &umount_list);
spin_unlock(&vfsmount_lock); spin_unlock(&vfsmount_lock);
up_write(&namespace_sem); up_write(&namespace_sem);
release_mounts(&umount_list); release_mounts(&umount_list);

View file

@ -574,14 +574,14 @@ void nfs_close_context(struct nfs_open_context *ctx, int is_sync)
nfs_revalidate_inode(server, inode); nfs_revalidate_inode(server, inode);
} }
static struct nfs_open_context *alloc_nfs_open_context(struct vfsmount *mnt, struct dentry *dentry, struct rpc_cred *cred) static struct nfs_open_context *alloc_nfs_open_context(struct path *path, struct rpc_cred *cred)
{ {
struct nfs_open_context *ctx; struct nfs_open_context *ctx;
ctx = kmalloc(sizeof(*ctx), GFP_KERNEL); ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
if (ctx != NULL) { if (ctx != NULL) {
ctx->path.dentry = dget(dentry); ctx->path = *path;
ctx->path.mnt = mntget(mnt); path_get(&ctx->path);
ctx->cred = get_rpccred(cred); ctx->cred = get_rpccred(cred);
ctx->state = NULL; ctx->state = NULL;
ctx->lockowner = current->files; ctx->lockowner = current->files;
@ -686,7 +686,7 @@ int nfs_open(struct inode *inode, struct file *filp)
cred = rpc_lookup_cred(); cred = rpc_lookup_cred();
if (IS_ERR(cred)) if (IS_ERR(cred))
return PTR_ERR(cred); return PTR_ERR(cred);
ctx = alloc_nfs_open_context(filp->f_path.mnt, filp->f_path.dentry, cred); ctx = alloc_nfs_open_context(&filp->f_path, cred);
put_rpccred(cred); put_rpccred(cred);
if (ctx == NULL) if (ctx == NULL)
return -ENOMEM; return -ENOMEM;

View file

@ -724,8 +724,8 @@ static struct nfs4_opendata *nfs4_opendata_alloc(struct path *path,
p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid); p->o_arg.seqid = nfs_alloc_seqid(&sp->so_seqid);
if (p->o_arg.seqid == NULL) if (p->o_arg.seqid == NULL)
goto err_free; goto err_free;
p->path.mnt = mntget(path->mnt); path_get(path);
p->path.dentry = dget(path->dentry); p->path = *path;
p->dir = parent; p->dir = parent;
p->owner = sp; p->owner = sp;
atomic_inc(&sp->so_count); atomic_inc(&sp->so_count);
@ -1944,8 +1944,8 @@ int nfs4_do_close(struct path *path, struct nfs4_state *state, int wait)
calldata->res.seqid = calldata->arg.seqid; calldata->res.seqid = calldata->arg.seqid;
calldata->res.server = server; calldata->res.server = server;
calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE; calldata->res.seq_res.sr_slotid = NFS4_MAX_SLOT_TABLE;
calldata->path.mnt = mntget(path->mnt); path_get(path);
calldata->path.dentry = dget(path->dentry); calldata->path = *path;
msg.rpc_argp = &calldata->arg, msg.rpc_argp = &calldata->arg,
msg.rpc_resp = &calldata->res, msg.rpc_resp = &calldata->res,

View file

@ -36,10 +36,9 @@ static struct file *do_open(char *name, int flags)
return ERR_PTR(error); return ERR_PTR(error);
if (flags == O_RDWR) if (flags == O_RDWR)
error = may_open(&nd.path, MAY_READ|MAY_WRITE, error = may_open(&nd.path, MAY_READ|MAY_WRITE, flags);
FMODE_READ|FMODE_WRITE);
else else
error = may_open(&nd.path, MAY_WRITE, FMODE_WRITE); error = may_open(&nd.path, MAY_WRITE, flags);
if (!error) if (!error)
return dentry_open(nd.path.dentry, nd.path.mnt, flags, return dentry_open(nd.path.dentry, nd.path.mnt, flags,

View file

@ -2121,9 +2121,15 @@ out_acl:
* and this is the root of a cross-mounted filesystem. * and this is the root of a cross-mounted filesystem.
*/ */
if (ignore_crossmnt == 0 && if (ignore_crossmnt == 0 &&
exp->ex_path.mnt->mnt_root->d_inode == dentry->d_inode) { dentry == exp->ex_path.mnt->mnt_root) {
err = vfs_getattr(exp->ex_path.mnt->mnt_parent, struct path path = exp->ex_path;
exp->ex_path.mnt->mnt_mountpoint, &stat); path_get(&path);
while (follow_up(&path)) {
if (path.dentry != path.mnt->mnt_root)
break;
}
err = vfs_getattr(path.mnt, path.dentry, &stat);
path_put(&path);
if (err) if (err)
goto out_nfserr; goto out_nfserr;
} }

View file

@ -361,7 +361,7 @@ nfsd_setattr(struct svc_rqst *rqstp, struct svc_fh *fhp, struct iattr *iap,
* If we are changing the size of the file, then * If we are changing the size of the file, then
* we need to break all leases. * we need to break all leases.
*/ */
host_err = break_lease(inode, FMODE_WRITE | O_NONBLOCK); host_err = break_lease(inode, O_WRONLY | O_NONBLOCK);
if (host_err == -EWOULDBLOCK) if (host_err == -EWOULDBLOCK)
host_err = -ETIMEDOUT; host_err = -ETIMEDOUT;
if (host_err) /* ENOMEM or EWOULDBLOCK */ if (host_err) /* ENOMEM or EWOULDBLOCK */
@ -734,7 +734,7 @@ nfsd_open(struct svc_rqst *rqstp, struct svc_fh *fhp, int type,
* Check to see if there are any leases on this file. * Check to see if there are any leases on this file.
* This may block while leases are broken. * This may block while leases are broken.
*/ */
host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? FMODE_WRITE : 0)); host_err = break_lease(inode, O_NONBLOCK | ((access & NFSD_MAY_WRITE) ? O_WRONLY : 0));
if (host_err == -EWOULDBLOCK) if (host_err == -EWOULDBLOCK)
host_err = -ETIMEDOUT; host_err = -ETIMEDOUT;
if (host_err) /* NOMEM or WOULDBLOCK */ if (host_err) /* NOMEM or WOULDBLOCK */

View file

@ -224,7 +224,7 @@ fail:
* len <= NILFS_NAME_LEN and de != NULL are guaranteed by caller. * len <= NILFS_NAME_LEN and de != NULL are guaranteed by caller.
*/ */
static int static int
nilfs_match(int len, const char * const name, struct nilfs_dir_entry *de) nilfs_match(int len, const unsigned char *name, struct nilfs_dir_entry *de)
{ {
if (len != de->name_len) if (len != de->name_len)
return 0; return 0;
@ -349,11 +349,11 @@ done:
* Entry is guaranteed to be valid. * Entry is guaranteed to be valid.
*/ */
struct nilfs_dir_entry * struct nilfs_dir_entry *
nilfs_find_entry(struct inode *dir, struct dentry *dentry, nilfs_find_entry(struct inode *dir, const struct qstr *qstr,
struct page **res_page) struct page **res_page)
{ {
const char *name = dentry->d_name.name; const unsigned char *name = qstr->name;
int namelen = dentry->d_name.len; int namelen = qstr->len;
unsigned reclen = NILFS_DIR_REC_LEN(namelen); unsigned reclen = NILFS_DIR_REC_LEN(namelen);
unsigned long start, n; unsigned long start, n;
unsigned long npages = dir_pages(dir); unsigned long npages = dir_pages(dir);
@ -424,13 +424,13 @@ struct nilfs_dir_entry *nilfs_dotdot(struct inode *dir, struct page **p)
return de; return de;
} }
ino_t nilfs_inode_by_name(struct inode *dir, struct dentry *dentry) ino_t nilfs_inode_by_name(struct inode *dir, const struct qstr *qstr)
{ {
ino_t res = 0; ino_t res = 0;
struct nilfs_dir_entry *de; struct nilfs_dir_entry *de;
struct page *page; struct page *page;
de = nilfs_find_entry(dir, dentry, &page); de = nilfs_find_entry(dir, qstr, &page);
if (de) { if (de) {
res = le64_to_cpu(de->inode); res = le64_to_cpu(de->inode);
kunmap(page); kunmap(page);
@ -465,7 +465,7 @@ void nilfs_set_link(struct inode *dir, struct nilfs_dir_entry *de,
int nilfs_add_link(struct dentry *dentry, struct inode *inode) int nilfs_add_link(struct dentry *dentry, struct inode *inode)
{ {
struct inode *dir = dentry->d_parent->d_inode; struct inode *dir = dentry->d_parent->d_inode;
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
int namelen = dentry->d_name.len; int namelen = dentry->d_name.len;
unsigned chunk_size = nilfs_chunk_size(dir); unsigned chunk_size = nilfs_chunk_size(dir);
unsigned reclen = NILFS_DIR_REC_LEN(namelen); unsigned reclen = NILFS_DIR_REC_LEN(namelen);

View file

@ -67,7 +67,7 @@ nilfs_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd)
if (dentry->d_name.len > NILFS_NAME_LEN) if (dentry->d_name.len > NILFS_NAME_LEN)
return ERR_PTR(-ENAMETOOLONG); return ERR_PTR(-ENAMETOOLONG);
ino = nilfs_inode_by_name(dir, dentry); ino = nilfs_inode_by_name(dir, &dentry->d_name);
inode = NULL; inode = NULL;
if (ino) { if (ino) {
inode = nilfs_iget(dir->i_sb, ino); inode = nilfs_iget(dir->i_sb, ino);
@ -81,10 +81,7 @@ struct dentry *nilfs_get_parent(struct dentry *child)
{ {
unsigned long ino; unsigned long ino;
struct inode *inode; struct inode *inode;
struct dentry dotdot; struct qstr dotdot = {.name = "..", .len = 2};
dotdot.d_name.name = "..";
dotdot.d_name.len = 2;
ino = nilfs_inode_by_name(child->d_inode, &dotdot); ino = nilfs_inode_by_name(child->d_inode, &dotdot);
if (!ino) if (!ino)
@ -296,7 +293,7 @@ static int nilfs_do_unlink(struct inode *dir, struct dentry *dentry)
int err; int err;
err = -ENOENT; err = -ENOENT;
de = nilfs_find_entry(dir, dentry, &page); de = nilfs_find_entry(dir, &dentry->d_name, &page);
if (!de) if (!de)
goto out; goto out;
@ -389,7 +386,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
return err; return err;
err = -ENOENT; err = -ENOENT;
old_de = nilfs_find_entry(old_dir, old_dentry, &old_page); old_de = nilfs_find_entry(old_dir, &old_dentry->d_name, &old_page);
if (!old_de) if (!old_de)
goto out; goto out;
@ -409,7 +406,7 @@ static int nilfs_rename(struct inode *old_dir, struct dentry *old_dentry,
goto out_dir; goto out_dir;
err = -ENOENT; err = -ENOENT;
new_de = nilfs_find_entry(new_dir, new_dentry, &new_page); new_de = nilfs_find_entry(new_dir, &new_dentry->d_name, &new_page);
if (!new_de) if (!new_de)
goto out_dir; goto out_dir;
inc_nlink(old_inode); inc_nlink(old_inode);

View file

@ -217,10 +217,10 @@ static inline int nilfs_init_acl(struct inode *inode, struct inode *dir)
/* dir.c */ /* dir.c */
extern int nilfs_add_link(struct dentry *, struct inode *); extern int nilfs_add_link(struct dentry *, struct inode *);
extern ino_t nilfs_inode_by_name(struct inode *, struct dentry *); extern ino_t nilfs_inode_by_name(struct inode *, const struct qstr *);
extern int nilfs_make_empty(struct inode *, struct inode *); extern int nilfs_make_empty(struct inode *, struct inode *);
extern struct nilfs_dir_entry * extern struct nilfs_dir_entry *
nilfs_find_entry(struct inode *, struct dentry *, struct page **); nilfs_find_entry(struct inode *, const struct qstr *, struct page **);
extern int nilfs_delete_entry(struct nilfs_dir_entry *, struct page *); extern int nilfs_delete_entry(struct nilfs_dir_entry *, struct page *);
extern int nilfs_empty_dir(struct inode *); extern int nilfs_empty_dir(struct inode *);
extern struct nilfs_dir_entry *nilfs_dotdot(struct inode *, struct page **); extern struct nilfs_dir_entry *nilfs_dotdot(struct inode *, struct page **);

View file

@ -29,14 +29,12 @@
#include <linux/init.h> /* module_init */ #include <linux/init.h> /* module_init */
#include <linux/inotify.h> #include <linux/inotify.h>
#include <linux/kernel.h> /* roundup() */ #include <linux/kernel.h> /* roundup() */
#include <linux/magic.h> /* superblock magic number */
#include <linux/mount.h> /* mntget */
#include <linux/namei.h> /* LOOKUP_FOLLOW */ #include <linux/namei.h> /* LOOKUP_FOLLOW */
#include <linux/path.h> /* struct path */
#include <linux/sched.h> /* struct user */ #include <linux/sched.h> /* struct user */
#include <linux/slab.h> /* struct kmem_cache */ #include <linux/slab.h> /* struct kmem_cache */
#include <linux/syscalls.h> #include <linux/syscalls.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/anon_inodes.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/poll.h> #include <linux/poll.h>
#include <linux/wait.h> #include <linux/wait.h>
@ -45,8 +43,6 @@
#include <asm/ioctls.h> #include <asm/ioctls.h>
static struct vfsmount *inotify_mnt __read_mostly;
/* these are configurable via /proc/sys/fs/inotify/ */ /* these are configurable via /proc/sys/fs/inotify/ */
static int inotify_max_user_instances __read_mostly; static int inotify_max_user_instances __read_mostly;
static int inotify_max_queued_events __read_mostly; static int inotify_max_queued_events __read_mostly;
@ -645,9 +641,7 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
{ {
struct fsnotify_group *group; struct fsnotify_group *group;
struct user_struct *user; struct user_struct *user;
struct file *filp; int ret;
struct path path;
int fd, ret;
/* Check the IN_* constants for consistency. */ /* Check the IN_* constants for consistency. */
BUILD_BUG_ON(IN_CLOEXEC != O_CLOEXEC); BUILD_BUG_ON(IN_CLOEXEC != O_CLOEXEC);
@ -656,10 +650,6 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
if (flags & ~(IN_CLOEXEC | IN_NONBLOCK)) if (flags & ~(IN_CLOEXEC | IN_NONBLOCK))
return -EINVAL; return -EINVAL;
fd = get_unused_fd_flags(flags & O_CLOEXEC);
if (fd < 0)
return fd;
user = get_current_user(); user = get_current_user();
if (unlikely(atomic_read(&user->inotify_devs) >= if (unlikely(atomic_read(&user->inotify_devs) >=
inotify_max_user_instances)) { inotify_max_user_instances)) {
@ -676,27 +666,14 @@ SYSCALL_DEFINE1(inotify_init1, int, flags)
atomic_inc(&user->inotify_devs); atomic_inc(&user->inotify_devs);
path.mnt = inotify_mnt; ret = anon_inode_getfd("inotify", &inotify_fops, group,
path.dentry = inotify_mnt->mnt_root; O_RDONLY | flags);
path_get(&path); if (ret >= 0)
filp = alloc_file(&path, FMODE_READ, &inotify_fops); return ret;
if (!filp)
goto Enfile;
filp->f_flags = O_RDONLY | (flags & O_NONBLOCK);
filp->private_data = group;
fd_install(fd, filp);
return fd;
Enfile:
ret = -ENFILE;
path_put(&path);
atomic_dec(&user->inotify_devs); atomic_dec(&user->inotify_devs);
out_free_uid: out_free_uid:
free_uid(user); free_uid(user);
put_unused_fd(fd);
return ret; return ret;
} }
@ -783,20 +760,6 @@ out:
return ret; return ret;
} }
static int
inotify_get_sb(struct file_system_type *fs_type, int flags,
const char *dev_name, void *data, struct vfsmount *mnt)
{
return get_sb_pseudo(fs_type, "inotify", NULL,
INOTIFYFS_SUPER_MAGIC, mnt);
}
static struct file_system_type inotify_fs_type = {
.name = "inotifyfs",
.get_sb = inotify_get_sb,
.kill_sb = kill_anon_super,
};
/* /*
* inotify_user_setup - Our initialization function. Note that we cannnot return * inotify_user_setup - Our initialization function. Note that we cannnot return
* error because we have compiled-in VFS hooks. So an (unlikely) failure here * error because we have compiled-in VFS hooks. So an (unlikely) failure here
@ -804,16 +767,6 @@ static struct file_system_type inotify_fs_type = {
*/ */
static int __init inotify_user_setup(void) static int __init inotify_user_setup(void)
{ {
int ret;
ret = register_filesystem(&inotify_fs_type);
if (unlikely(ret))
panic("inotify: register_filesystem returned %d!\n", ret);
inotify_mnt = kern_mount(&inotify_fs_type);
if (IS_ERR(inotify_mnt))
panic("inotify: kern_mount ret %ld!\n", PTR_ERR(inotify_mnt));
inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC); inotify_inode_mark_cachep = KMEM_CACHE(inotify_inode_mark_entry, SLAB_PANIC);
event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC); event_priv_cachep = KMEM_CACHE(inotify_event_private_data, SLAB_PANIC);

View file

@ -271,7 +271,7 @@ static long do_sys_truncate(const char __user *pathname, loff_t length)
* Make sure that there are no leases. get_write_access() protects * Make sure that there are no leases. get_write_access() protects
* against the truncate racing with a lease-granting setlease(). * against the truncate racing with a lease-granting setlease().
*/ */
error = break_lease(inode, FMODE_WRITE); error = break_lease(inode, O_WRONLY);
if (error) if (error)
goto put_write_and_out; goto put_write_and_out;

View file

@ -86,7 +86,7 @@ static int do_make_slave(struct vfsmount *mnt)
/* /*
* slave 'mnt' to a peer mount that has the * slave 'mnt' to a peer mount that has the
* same root dentry. If none is available than * same root dentry. If none is available then
* slave it to anything that is available. * slave it to anything that is available.
*/ */
while ((peer_mnt = next_peer(peer_mnt)) != mnt && while ((peer_mnt = next_peer(peer_mnt)) != mnt &&
@ -147,6 +147,11 @@ void change_mnt_propagation(struct vfsmount *mnt, int type)
* get the next mount in the propagation tree. * get the next mount in the propagation tree.
* @m: the mount seen last * @m: the mount seen last
* @origin: the original mount from where the tree walk initiated * @origin: the original mount from where the tree walk initiated
*
* Note that peer groups form contiguous segments of slave lists.
* We rely on that in get_source() to be able to find out if
* vfsmount found while iterating with propagation_next() is
* a peer of one we'd found earlier.
*/ */
static struct vfsmount *propagation_next(struct vfsmount *m, static struct vfsmount *propagation_next(struct vfsmount *m,
struct vfsmount *origin) struct vfsmount *origin)
@ -186,10 +191,6 @@ static struct vfsmount *get_source(struct vfsmount *dest,
{ {
struct vfsmount *p_last_src = NULL; struct vfsmount *p_last_src = NULL;
struct vfsmount *p_last_dest = NULL; struct vfsmount *p_last_dest = NULL;
*type = CL_PROPAGATION;
if (IS_MNT_SHARED(dest))
*type |= CL_MAKE_SHARED;
while (last_dest != dest->mnt_master) { while (last_dest != dest->mnt_master) {
p_last_dest = last_dest; p_last_dest = last_dest;
@ -202,13 +203,18 @@ static struct vfsmount *get_source(struct vfsmount *dest,
do { do {
p_last_dest = next_peer(p_last_dest); p_last_dest = next_peer(p_last_dest);
} while (IS_MNT_NEW(p_last_dest)); } while (IS_MNT_NEW(p_last_dest));
/* is that a peer of the earlier? */
if (dest == p_last_dest) {
*type = CL_MAKE_SHARED;
return p_last_src;
}
} }
/* slave of the earlier, then */
if (dest != p_last_dest) { *type = CL_SLAVE;
*type |= CL_SLAVE; /* beginning of peer group among the slaves? */
return last_src; if (IS_MNT_SHARED(dest))
} else *type |= CL_MAKE_SHARED;
return p_last_src; return last_src;
} }
/* /*

View file

@ -21,12 +21,11 @@
#define CL_SLAVE 0x02 #define CL_SLAVE 0x02
#define CL_COPY_ALL 0x04 #define CL_COPY_ALL 0x04
#define CL_MAKE_SHARED 0x08 #define CL_MAKE_SHARED 0x08
#define CL_PROPAGATION 0x10 #define CL_PRIVATE 0x10
#define CL_PRIVATE 0x20
static inline void set_mnt_shared(struct vfsmount *mnt) static inline void set_mnt_shared(struct vfsmount *mnt)
{ {
mnt->mnt_flags &= ~MNT_PNODE_MASK; mnt->mnt_flags &= ~MNT_SHARED_MASK;
mnt->mnt_flags |= MNT_SHARED; mnt->mnt_flags |= MNT_SHARED;
} }

View file

@ -647,17 +647,11 @@ static int mounts_release(struct inode *inode, struct file *file)
static unsigned mounts_poll(struct file *file, poll_table *wait) static unsigned mounts_poll(struct file *file, poll_table *wait)
{ {
struct proc_mounts *p = file->private_data; struct proc_mounts *p = file->private_data;
struct mnt_namespace *ns = p->ns;
unsigned res = POLLIN | POLLRDNORM; unsigned res = POLLIN | POLLRDNORM;
poll_wait(file, &ns->poll, wait); poll_wait(file, &p->ns->poll, wait);
if (mnt_had_events(p))
spin_lock(&vfsmount_lock);
if (p->event != ns->event) {
p->event = ns->event;
res |= POLLERR | POLLPRI; res |= POLLERR | POLLPRI;
}
spin_unlock(&vfsmount_lock);
return res; return res;
} }

View file

@ -662,6 +662,7 @@ struct proc_dir_entry *proc_symlink(const char *name,
} }
return ent; return ent;
} }
EXPORT_SYMBOL(proc_symlink);
struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode, struct proc_dir_entry *proc_mkdir_mode(const char *name, mode_t mode,
struct proc_dir_entry *parent) struct proc_dir_entry *parent)
@ -700,6 +701,7 @@ struct proc_dir_entry *proc_mkdir(const char *name,
{ {
return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent); return proc_mkdir_mode(name, S_IRUGO | S_IXUGO, parent);
} }
EXPORT_SYMBOL(proc_mkdir);
struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode, struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
struct proc_dir_entry *parent) struct proc_dir_entry *parent)
@ -728,6 +730,7 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
} }
return ent; return ent;
} }
EXPORT_SYMBOL(create_proc_entry);
struct proc_dir_entry *proc_create_data(const char *name, mode_t mode, struct proc_dir_entry *proc_create_data(const char *name, mode_t mode,
struct proc_dir_entry *parent, struct proc_dir_entry *parent,
@ -762,6 +765,7 @@ out_free:
out: out:
return NULL; return NULL;
} }
EXPORT_SYMBOL(proc_create_data);
static void free_proc_entry(struct proc_dir_entry *de) static void free_proc_entry(struct proc_dir_entry *de)
{ {
@ -853,3 +857,4 @@ continue_removing:
de->parent->name, de->name, de->subdir->name); de->parent->name, de->name, de->subdir->name);
pde_put(de); pde_put(de);
} }
EXPORT_SYMBOL(remove_proc_entry);

View file

@ -220,9 +220,3 @@ void pid_ns_release_proc(struct pid_namespace *ns)
{ {
mntput(ns->proc_mnt); mntput(ns->proc_mnt);
} }
EXPORT_SYMBOL(proc_symlink);
EXPORT_SYMBOL(proc_mkdir);
EXPORT_SYMBOL(create_proc_entry);
EXPORT_SYMBOL(proc_create_data);
EXPORT_SYMBOL(remove_proc_entry);

View file

@ -568,7 +568,7 @@ out:
int do_remount_sb(struct super_block *sb, int flags, void *data, int force) int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
{ {
int retval; int retval;
int remount_rw; int remount_rw, remount_ro;
if (sb->s_frozen != SB_UNFROZEN) if (sb->s_frozen != SB_UNFROZEN)
return -EBUSY; return -EBUSY;
@ -583,9 +583,12 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
shrink_dcache_sb(sb); shrink_dcache_sb(sb);
sync_filesystem(sb); sync_filesystem(sb);
remount_ro = (flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY);
remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
/* If we are remounting RDONLY and current sb is read/write, /* If we are remounting RDONLY and current sb is read/write,
make sure there are no rw files opened */ make sure there are no rw files opened */
if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) { if (remount_ro) {
if (force) if (force)
mark_files_ro(sb); mark_files_ro(sb);
else if (!fs_may_remount_ro(sb)) else if (!fs_may_remount_ro(sb))
@ -594,7 +597,6 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
if (retval < 0 && retval != -ENOSYS) if (retval < 0 && retval != -ENOSYS)
return -EBUSY; return -EBUSY;
} }
remount_rw = !(flags & MS_RDONLY) && (sb->s_flags & MS_RDONLY);
if (sb->s_op->remount_fs) { if (sb->s_op->remount_fs) {
retval = sb->s_op->remount_fs(sb, &flags, data); retval = sb->s_op->remount_fs(sb, &flags, data);
@ -604,6 +606,16 @@ int do_remount_sb(struct super_block *sb, int flags, void *data, int force)
sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK); sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | (flags & MS_RMT_MASK);
if (remount_rw) if (remount_rw)
vfs_dq_quota_on_remount(sb); vfs_dq_quota_on_remount(sb);
/*
* Some filesystems modify their metadata via some other path than the
* bdev buffer cache (eg. use a private mapping, or directories in
* pagecache, etc). Also file data modifications go via their own
* mappings. So If we try to mount readonly then copy the filesystem
* from bdev, we could get stale data, so invalidate it to give a best
* effort at coherency.
*/
if (remount_ro && sb->s_bdev)
invalidate_bdev(sb->s_bdev);
return 0; return 0;
} }
@ -925,6 +937,9 @@ vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void
if (!mnt) if (!mnt)
goto out; goto out;
if (flags & MS_KERNMOUNT)
mnt->mnt_flags = MNT_INTERNAL;
if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) { if (data && !(type->fs_flags & FS_BINARY_MOUNTDATA)) {
secdata = alloc_secdata(); secdata = alloc_secdata();
if (!secdata) if (!secdata)

View file

@ -547,7 +547,7 @@ static void udf_table_free_blocks(struct super_block *sb,
} }
if (epos.offset + (2 * adsize) > sb->s_blocksize) { if (epos.offset + (2 * adsize) > sb->s_blocksize) {
char *sptr, *dptr; unsigned char *sptr, *dptr;
int loffset; int loffset;
brelse(oepos.bh); brelse(oepos.bh);

View file

@ -45,8 +45,8 @@ static int do_udf_readdir(struct inode *dir, struct file *filp,
int block, iblock; int block, iblock;
loff_t nf_pos = (filp->f_pos - 1) << 2; loff_t nf_pos = (filp->f_pos - 1) << 2;
int flen; int flen;
char *fname = NULL; unsigned char *fname = NULL;
char *nameptr; unsigned char *nameptr;
uint16_t liu; uint16_t liu;
uint8_t lfi; uint8_t lfi;
loff_t size = udf_ext0_offset(dir) + dir->i_size; loff_t size = udf_ext0_offset(dir) + dir->i_size;

View file

@ -1672,7 +1672,7 @@ int8_t udf_add_aext(struct inode *inode, struct extent_position *epos,
return -1; return -1;
if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) { if (epos->offset + (2 * adsize) > inode->i_sb->s_blocksize) {
char *sptr, *dptr; unsigned char *sptr, *dptr;
struct buffer_head *nbh; struct buffer_head *nbh;
int err, loffset; int err, loffset;
struct kernel_lb_addr obloc = epos->block; struct kernel_lb_addr obloc = epos->block;

View file

@ -34,8 +34,8 @@
#include <linux/crc-itu-t.h> #include <linux/crc-itu-t.h>
#include <linux/exportfs.h> #include <linux/exportfs.h>
static inline int udf_match(int len1, const char *name1, int len2, static inline int udf_match(int len1, const unsigned char *name1, int len2,
const char *name2) const unsigned char *name2)
{ {
if (len1 != len2) if (len1 != len2)
return 0; return 0;
@ -142,15 +142,15 @@ int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
} }
static struct fileIdentDesc *udf_find_entry(struct inode *dir, static struct fileIdentDesc *udf_find_entry(struct inode *dir,
struct qstr *child, const struct qstr *child,
struct udf_fileident_bh *fibh, struct udf_fileident_bh *fibh,
struct fileIdentDesc *cfi) struct fileIdentDesc *cfi)
{ {
struct fileIdentDesc *fi = NULL; struct fileIdentDesc *fi = NULL;
loff_t f_pos; loff_t f_pos;
int block, flen; int block, flen;
char *fname = NULL; unsigned char *fname = NULL;
char *nameptr; unsigned char *nameptr;
uint8_t lfi; uint8_t lfi;
uint16_t liu; uint16_t liu;
loff_t size; loff_t size;
@ -308,7 +308,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir,
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
struct fileIdentDesc *fi = NULL; struct fileIdentDesc *fi = NULL;
char *name = NULL; unsigned char *name = NULL;
int namelen; int namelen;
loff_t f_pos; loff_t f_pos;
loff_t size = udf_ext0_offset(dir) + dir->i_size; loff_t size = udf_ext0_offset(dir) + dir->i_size;
@ -885,16 +885,16 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
{ {
struct inode *inode; struct inode *inode;
struct pathComponent *pc; struct pathComponent *pc;
char *compstart; const char *compstart;
struct udf_fileident_bh fibh; struct udf_fileident_bh fibh;
struct extent_position epos = {}; struct extent_position epos = {};
int eoffset, elen = 0; int eoffset, elen = 0;
struct fileIdentDesc *fi; struct fileIdentDesc *fi;
struct fileIdentDesc cfi; struct fileIdentDesc cfi;
char *ea; uint8_t *ea;
int err; int err;
int block; int block;
char *name = NULL; unsigned char *name = NULL;
int namelen; int namelen;
struct buffer_head *bh; struct buffer_head *bh;
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
@ -970,7 +970,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry,
pc = (struct pathComponent *)(ea + elen); pc = (struct pathComponent *)(ea + elen);
compstart = (char *)symname; compstart = symname;
do { do {
symname++; symname++;

View file

@ -32,12 +32,12 @@
#include <linux/buffer_head.h> #include <linux/buffer_head.h>
#include "udf_i.h" #include "udf_i.h"
static void udf_pc_to_char(struct super_block *sb, char *from, int fromlen, static void udf_pc_to_char(struct super_block *sb, unsigned char *from,
char *to) int fromlen, unsigned char *to)
{ {
struct pathComponent *pc; struct pathComponent *pc;
int elen = 0; int elen = 0;
char *p = to; unsigned char *p = to;
while (elen < fromlen) { while (elen < fromlen) {
pc = (struct pathComponent *)(from + elen); pc = (struct pathComponent *)(from + elen);
@ -75,9 +75,9 @@ static int udf_symlink_filler(struct file *file, struct page *page)
{ {
struct inode *inode = page->mapping->host; struct inode *inode = page->mapping->host;
struct buffer_head *bh = NULL; struct buffer_head *bh = NULL;
char *symlink; unsigned char *symlink;
int err = -EIO; int err = -EIO;
char *p = kmap(page); unsigned char *p = kmap(page);
struct udf_inode_info *iinfo; struct udf_inode_info *iinfo;
lock_kernel(); lock_kernel();

View file

@ -31,7 +31,7 @@
* len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller. * len <= UFS_MAXNAMLEN and de != NULL are guaranteed by caller.
*/ */
static inline int ufs_match(struct super_block *sb, int len, static inline int ufs_match(struct super_block *sb, int len,
const char * const name, struct ufs_dir_entry * de) const unsigned char *name, struct ufs_dir_entry *de)
{ {
if (len != ufs_get_de_namlen(sb, de)) if (len != ufs_get_de_namlen(sb, de))
return 0; return 0;
@ -70,7 +70,7 @@ static inline unsigned long ufs_dir_pages(struct inode *inode)
return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT; return (inode->i_size+PAGE_CACHE_SIZE-1)>>PAGE_CACHE_SHIFT;
} }
ino_t ufs_inode_by_name(struct inode *dir, struct qstr *qstr) ino_t ufs_inode_by_name(struct inode *dir, const struct qstr *qstr)
{ {
ino_t res = 0; ino_t res = 0;
struct ufs_dir_entry *de; struct ufs_dir_entry *de;
@ -249,11 +249,11 @@ struct ufs_dir_entry *ufs_dotdot(struct inode *dir, struct page **p)
* (as a parameter - res_dir). Page is returned mapped and unlocked. * (as a parameter - res_dir). Page is returned mapped and unlocked.
* Entry is guaranteed to be valid. * Entry is guaranteed to be valid.
*/ */
struct ufs_dir_entry *ufs_find_entry(struct inode *dir, struct qstr *qstr, struct ufs_dir_entry *ufs_find_entry(struct inode *dir, const struct qstr *qstr,
struct page **res_page) struct page **res_page)
{ {
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
const char *name = qstr->name; const unsigned char *name = qstr->name;
int namelen = qstr->len; int namelen = qstr->len;
unsigned reclen = UFS_DIR_REC_LEN(namelen); unsigned reclen = UFS_DIR_REC_LEN(namelen);
unsigned long start, n; unsigned long start, n;
@ -313,7 +313,7 @@ found:
int ufs_add_link(struct dentry *dentry, struct inode *inode) int ufs_add_link(struct dentry *dentry, struct inode *inode)
{ {
struct inode *dir = dentry->d_parent->d_inode; struct inode *dir = dentry->d_parent->d_inode;
const char *name = dentry->d_name.name; const unsigned char *name = dentry->d_name.name;
int namelen = dentry->d_name.len; int namelen = dentry->d_name.len;
struct super_block *sb = dir->i_sb; struct super_block *sb = dir->i_sb;
unsigned reclen = UFS_DIR_REC_LEN(namelen); unsigned reclen = UFS_DIR_REC_LEN(namelen);

View file

@ -86,9 +86,9 @@ extern void ufs_put_cylinder (struct super_block *, unsigned);
/* dir.c */ /* dir.c */
extern const struct inode_operations ufs_dir_inode_operations; extern const struct inode_operations ufs_dir_inode_operations;
extern int ufs_add_link (struct dentry *, struct inode *); extern int ufs_add_link (struct dentry *, struct inode *);
extern ino_t ufs_inode_by_name(struct inode *, struct qstr *); extern ino_t ufs_inode_by_name(struct inode *, const struct qstr *);
extern int ufs_make_empty(struct inode *, struct inode *); extern int ufs_make_empty(struct inode *, struct inode *);
extern struct ufs_dir_entry *ufs_find_entry(struct inode *, struct qstr *, struct page **); extern struct ufs_dir_entry *ufs_find_entry(struct inode *, const struct qstr *, struct page **);
extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *); extern int ufs_delete_entry(struct inode *, struct ufs_dir_entry *, struct page *);
extern int ufs_empty_dir (struct inode *); extern int ufs_empty_dir (struct inode *);
extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **); extern struct ufs_dir_entry *ufs_dotdot(struct inode *, struct page **);

View file

@ -424,7 +424,7 @@ extern void audit_syscall_exit(int failed, long return_code);
extern void __audit_getname(const char *name); extern void __audit_getname(const char *name);
extern void audit_putname(const char *name); extern void audit_putname(const char *name);
extern void __audit_inode(const char *name, const struct dentry *dentry); extern void __audit_inode(const char *name, const struct dentry *dentry);
extern void __audit_inode_child(const char *dname, const struct dentry *dentry, extern void __audit_inode_child(const struct dentry *dentry,
const struct inode *parent); const struct inode *parent);
extern void __audit_ptrace(struct task_struct *t); extern void __audit_ptrace(struct task_struct *t);
@ -442,11 +442,10 @@ static inline void audit_inode(const char *name, const struct dentry *dentry) {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
__audit_inode(name, dentry); __audit_inode(name, dentry);
} }
static inline void audit_inode_child(const char *dname, static inline void audit_inode_child(const struct dentry *dentry,
const struct dentry *dentry,
const struct inode *parent) { const struct inode *parent) {
if (unlikely(!audit_dummy_context())) if (unlikely(!audit_dummy_context()))
__audit_inode_child(dname, dentry, parent); __audit_inode_child(dentry, parent);
} }
void audit_core_dumps(long signr); void audit_core_dumps(long signr);
@ -544,9 +543,9 @@ extern int audit_signals;
#define audit_getname(n) do { ; } while (0) #define audit_getname(n) do { ; } while (0)
#define audit_putname(n) do { ; } while (0) #define audit_putname(n) do { ; } while (0)
#define __audit_inode(n,d) do { ; } while (0) #define __audit_inode(n,d) do { ; } while (0)
#define __audit_inode_child(d,i,p) do { ; } while (0) #define __audit_inode_child(i,p) do { ; } while (0)
#define audit_inode(n,d) do { ; } while (0) #define audit_inode(n,d) do { ; } while (0)
#define audit_inode_child(d,i,p) do { ; } while (0) #define audit_inode_child(i,p) do { ; } while (0)
#define audit_core_dumps(i) do { ; } while (0) #define audit_core_dumps(i) do { ; } while (0)
#define auditsc_get_stamp(c,t,s) (0) #define auditsc_get_stamp(c,t,s) (0)
#define audit_get_loginuid(t) (-1) #define audit_get_loginuid(t) (-1)

View file

@ -1305,6 +1305,8 @@ extern int send_sigurg(struct fown_struct *fown);
#define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */ #define MNT_FORCE 0x00000001 /* Attempt to forcibily umount */
#define MNT_DETACH 0x00000002 /* Just detach from the tree */ #define MNT_DETACH 0x00000002 /* Just detach from the tree */
#define MNT_EXPIRE 0x00000004 /* Mark for expiry */ #define MNT_EXPIRE 0x00000004 /* Mark for expiry */
#define UMOUNT_NOFOLLOW 0x00000008 /* Don't follow symlink on umount */
#define UMOUNT_UNUSED 0x80000000 /* Flag guaranteed to be unused */
extern struct list_head super_blocks; extern struct list_head super_blocks;
extern spinlock_t sb_lock; extern spinlock_t sb_lock;
@ -1314,9 +1316,9 @@ extern spinlock_t sb_lock;
struct super_block { struct super_block {
struct list_head s_list; /* Keep this first */ struct list_head s_list; /* Keep this first */
dev_t s_dev; /* search index; _not_ kdev_t */ dev_t s_dev; /* search index; _not_ kdev_t */
unsigned long s_blocksize;
unsigned char s_blocksize_bits;
unsigned char s_dirt; unsigned char s_dirt;
unsigned char s_blocksize_bits;
unsigned long s_blocksize;
loff_t s_maxbytes; /* Max file size */ loff_t s_maxbytes; /* Max file size */
struct file_system_type *s_type; struct file_system_type *s_type;
const struct super_operations *s_op; const struct super_operations *s_op;
@ -1357,16 +1359,16 @@ struct super_block {
void *s_fs_info; /* Filesystem private info */ void *s_fs_info; /* Filesystem private info */
fmode_t s_mode; fmode_t s_mode;
/* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran;
/* /*
* The next field is for VFS *only*. No filesystems have any business * The next field is for VFS *only*. No filesystems have any business
* even looking at it. You had been warned. * even looking at it. You had been warned.
*/ */
struct mutex s_vfs_rename_mutex; /* Kludge */ struct mutex s_vfs_rename_mutex; /* Kludge */
/* Granularity of c/m/atime in ns.
Cannot be worse than a second */
u32 s_time_gran;
/* /*
* Filesystem subtype. If non-empty the filesystem type field * Filesystem subtype. If non-empty the filesystem type field
* in /proc/mounts will be "type.subtype" * in /proc/mounts will be "type.subtype"
@ -1794,7 +1796,8 @@ extern int may_umount(struct vfsmount *);
extern long do_mount(char *, char *, char *, unsigned long, void *); extern long do_mount(char *, char *, char *, unsigned long, void *);
extern struct vfsmount *collect_mounts(struct path *); extern struct vfsmount *collect_mounts(struct path *);
extern void drop_collected_mounts(struct vfsmount *); extern void drop_collected_mounts(struct vfsmount *);
extern int iterate_mounts(int (*)(struct vfsmount *, void *), void *,
struct vfsmount *);
extern int vfs_statfs(struct dentry *, struct kstatfs *); extern int vfs_statfs(struct dentry *, struct kstatfs *);
extern int current_umask(void); extern int current_umask(void);
@ -2058,12 +2061,6 @@ extern int invalidate_inodes(struct super_block *);
unsigned long invalidate_mapping_pages(struct address_space *mapping, unsigned long invalidate_mapping_pages(struct address_space *mapping,
pgoff_t start, pgoff_t end); pgoff_t start, pgoff_t end);
static inline unsigned long __deprecated
invalidate_inode_pages(struct address_space *mapping)
{
return invalidate_mapping_pages(mapping, 0, ~0UL);
}
static inline void invalidate_remote_inode(struct inode *inode) static inline void invalidate_remote_inode(struct inode *inode)
{ {
if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || if (S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) ||
@ -2132,6 +2129,7 @@ extern struct file * open_exec(const char *);
/* fs/dcache.c -- generic fs support functions */ /* fs/dcache.c -- generic fs support functions */
extern int is_subdir(struct dentry *, struct dentry *); extern int is_subdir(struct dentry *, struct dentry *);
extern int path_is_under(struct path *, struct path *);
extern ino_t find_inode_number(struct dentry *, struct qstr *); extern ino_t find_inode_number(struct dentry *, struct qstr *);
#include <linux/err.h> #include <linux/err.h>
@ -2340,8 +2338,6 @@ extern int simple_rename(struct inode *, struct dentry *, struct inode *, struct
extern int simple_sync_file(struct file *, struct dentry *, int); extern int simple_sync_file(struct file *, struct dentry *, int);
extern int simple_empty(struct dentry *); extern int simple_empty(struct dentry *);
extern int simple_readpage(struct file *file, struct page *page); extern int simple_readpage(struct file *file, struct page *page);
extern int simple_prepare_write(struct file *file, struct page *page,
unsigned offset, unsigned to);
extern int simple_write_begin(struct file *file, struct address_space *mapping, extern int simple_write_begin(struct file *file, struct address_space *mapping,
loff_t pos, unsigned len, unsigned flags, loff_t pos, unsigned len, unsigned flags,
struct page **pagep, void **fsdata); struct page **pagep, void **fsdata);

View file

@ -65,7 +65,7 @@ static inline void fsnotify_link_count(struct inode *inode)
* fsnotify_move - file old_name at old_dir was moved to new_name at new_dir * fsnotify_move - file old_name at old_dir was moved to new_name at new_dir
*/ */
static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir, static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
const char *old_name, const char *new_name, const char *old_name,
int isdir, struct inode *target, struct dentry *moved) int isdir, struct inode *target, struct dentry *moved)
{ {
struct inode *source = moved->d_inode; struct inode *source = moved->d_inode;
@ -73,6 +73,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
u32 fs_cookie = fsnotify_get_cookie(); u32 fs_cookie = fsnotify_get_cookie();
__u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM); __u32 old_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_FROM);
__u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO); __u32 new_dir_mask = (FS_EVENT_ON_CHILD | FS_MOVED_TO);
const char *new_name = moved->d_name.name;
if (old_dir == new_dir) if (old_dir == new_dir)
old_dir_mask |= FS_DN_RENAME; old_dir_mask |= FS_DN_RENAME;
@ -103,7 +104,7 @@ static inline void fsnotify_move(struct inode *old_dir, struct inode *new_dir,
inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL); inotify_inode_queue_event(source, IN_MOVE_SELF, 0, NULL, NULL);
fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0); fsnotify(source, FS_MOVE_SELF, moved->d_inode, FSNOTIFY_EVENT_INODE, NULL, 0);
} }
audit_inode_child(new_name, moved, new_dir); audit_inode_child(moved, new_dir);
} }
/* /*
@ -146,7 +147,7 @@ static inline void fsnotify_create(struct inode *inode, struct dentry *dentry)
{ {
inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name, inotify_inode_queue_event(inode, IN_CREATE, 0, dentry->d_name.name,
dentry->d_inode); dentry->d_inode);
audit_inode_child(dentry->d_name.name, dentry, inode); audit_inode_child(dentry, inode);
fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); fsnotify(inode, FS_CREATE, dentry->d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
} }
@ -161,7 +162,7 @@ static inline void fsnotify_link(struct inode *dir, struct inode *inode, struct
inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name, inotify_inode_queue_event(dir, IN_CREATE, 0, new_dentry->d_name.name,
inode); inode);
fsnotify_link_count(inode); fsnotify_link_count(inode);
audit_inode_child(new_dentry->d_name.name, new_dentry, dir); audit_inode_child(new_dentry, dir);
fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0); fsnotify(dir, FS_CREATE, inode, FSNOTIFY_EVENT_INODE, new_dentry->d_name.name, 0);
} }
@ -175,7 +176,7 @@ static inline void fsnotify_mkdir(struct inode *inode, struct dentry *dentry)
struct inode *d_inode = dentry->d_inode; struct inode *d_inode = dentry->d_inode;
inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode); inotify_inode_queue_event(inode, mask, 0, dentry->d_name.name, d_inode);
audit_inode_child(dentry->d_name.name, dentry, inode); audit_inode_child(dentry, inode);
fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0); fsnotify(inode, mask, d_inode, FSNOTIFY_EVENT_INODE, dentry->d_name.name, 0);
} }

View file

@ -52,7 +52,6 @@
#define CGROUP_SUPER_MAGIC 0x27e0eb #define CGROUP_SUPER_MAGIC 0x27e0eb
#define FUTEXFS_SUPER_MAGIC 0xBAD1DEA #define FUTEXFS_SUPER_MAGIC 0xBAD1DEA
#define INOTIFYFS_SUPER_MAGIC 0x2BAD1DEA
#define STACK_END_MAGIC 0x57AC6E9D #define STACK_END_MAGIC 0x57AC6E9D

View file

@ -35,6 +35,7 @@ static inline void get_mnt_ns(struct mnt_namespace *ns)
extern const struct seq_operations mounts_op; extern const struct seq_operations mounts_op;
extern const struct seq_operations mountinfo_op; extern const struct seq_operations mountinfo_op;
extern const struct seq_operations mountstats_op; extern const struct seq_operations mountstats_op;
extern int mnt_had_events(struct proc_mounts *);
#endif #endif
#endif #endif

View file

@ -34,7 +34,18 @@ struct mnt_namespace;
#define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */ #define MNT_SHARED 0x1000 /* if the vfsmount is a shared mount */
#define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */
#define MNT_PNODE_MASK 0x3000 /* propagation flag mask */ /*
* MNT_SHARED_MASK is the set of flags that should be cleared when a
* mount becomes shared. Currently, this is only the flag that says a
* mount cannot be bind mounted, since this is how we create a mount
* that shares events with another mount. If you add a new MNT_*
* flag, consider how it interacts with shared mounts.
*/
#define MNT_SHARED_MASK (MNT_UNBINDABLE)
#define MNT_PROPAGATION_MASK (MNT_SHARED | MNT_UNBINDABLE)
#define MNT_INTERNAL 0x4000
struct vfsmount { struct vfsmount {
struct list_head mnt_hash; struct list_head mnt_hash;
@ -123,7 +134,6 @@ extern int do_add_mount(struct vfsmount *newmnt, struct path *path,
extern void mark_mounts_for_expiry(struct list_head *mounts); extern void mark_mounts_for_expiry(struct list_head *mounts);
extern spinlock_t vfsmount_lock;
extern dev_t name_to_dev_t(char *name); extern dev_t name_to_dev_t(char *name);
#endif /* _LINUX_MOUNT_H */ #endif /* _LINUX_MOUNT_H */

View file

@ -30,11 +30,7 @@ static int __init do_linuxrc(void * shell)
extern char * envp_init[]; extern char * envp_init[];
sys_close(old_fd);sys_close(root_fd); sys_close(old_fd);sys_close(root_fd);
sys_close(0);sys_close(1);sys_close(2);
sys_setsid(); sys_setsid();
(void) sys_open("/dev/console",O_RDWR,0);
(void) sys_dup(0);
(void) sys_dup(0);
return kernel_execve(shell, argv, envp_init); return kernel_execve(shell, argv, envp_init);
} }

View file

@ -822,11 +822,6 @@ static noinline int init_post(void)
system_state = SYSTEM_RUNNING; system_state = SYSTEM_RUNNING;
numa_default_policy(); numa_default_policy();
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
current->signal->flags |= SIGNAL_UNKILLABLE; current->signal->flags |= SIGNAL_UNKILLABLE;
@ -889,6 +884,12 @@ static int __init kernel_init(void * unused)
do_basic_setup(); do_basic_setup();
/* Open the /dev/console on the rootfs, this should never fail */
if (sys_open((const char __user *) "/dev/console", O_RDWR, 0) < 0)
printk(KERN_WARNING "Warning: unable to open an initial console.\n");
(void) sys_dup(0);
(void) sys_dup(0);
/* /*
* check if there is an early userspace init. If yes, let it do all * check if there is an early userspace init. If yes, let it do all
* the work * the work

View file

@ -134,7 +134,6 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
init_waitqueue_head(&info->wait_q); init_waitqueue_head(&info->wait_q);
INIT_LIST_HEAD(&info->e_wait_q[0].list); INIT_LIST_HEAD(&info->e_wait_q[0].list);
INIT_LIST_HEAD(&info->e_wait_q[1].list); INIT_LIST_HEAD(&info->e_wait_q[1].list);
info->messages = NULL;
info->notify_owner = NULL; info->notify_owner = NULL;
info->qsize = 0; info->qsize = 0;
info->user = NULL; /* set when all is ok */ info->user = NULL; /* set when all is ok */
@ -146,6 +145,10 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
info->attr.mq_msgsize = attr->mq_msgsize; info->attr.mq_msgsize = attr->mq_msgsize;
} }
mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *); mq_msg_tblsz = info->attr.mq_maxmsg * sizeof(struct msg_msg *);
info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
if (!info->messages)
goto out_inode;
mq_bytes = (mq_msg_tblsz + mq_bytes = (mq_msg_tblsz +
(info->attr.mq_maxmsg * info->attr.mq_msgsize)); (info->attr.mq_maxmsg * info->attr.mq_msgsize));
@ -154,18 +157,12 @@ static struct inode *mqueue_get_inode(struct super_block *sb,
u->mq_bytes + mq_bytes > u->mq_bytes + mq_bytes >
p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) { p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) {
spin_unlock(&mq_lock); spin_unlock(&mq_lock);
kfree(info->messages);
goto out_inode; goto out_inode;
} }
u->mq_bytes += mq_bytes; u->mq_bytes += mq_bytes;
spin_unlock(&mq_lock); spin_unlock(&mq_lock);
info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL);
if (!info->messages) {
spin_lock(&mq_lock);
u->mq_bytes -= mq_bytes;
spin_unlock(&mq_lock);
goto out_inode;
}
/* all is ok */ /* all is ok */
info->user = get_uid(u); info->user = get_uid(u);
} else if (S_ISDIR(mode)) { } else if (S_ISDIR(mode)) {
@ -187,7 +184,7 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
{ {
struct inode *inode; struct inode *inode;
struct ipc_namespace *ns = data; struct ipc_namespace *ns = data;
int error = 0; int error;
sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize = PAGE_CACHE_SIZE;
sb->s_blocksize_bits = PAGE_CACHE_SHIFT; sb->s_blocksize_bits = PAGE_CACHE_SHIFT;
@ -205,7 +202,9 @@ static int mqueue_fill_super(struct super_block *sb, void *data, int silent)
if (!sb->s_root) { if (!sb->s_root) {
iput(inode); iput(inode);
error = -ENOMEM; error = -ENOMEM;
goto out;
} }
error = 0;
out: out:
return error; return error;
@ -264,8 +263,9 @@ static void mqueue_delete_inode(struct inode *inode)
clear_inode(inode); clear_inode(inode);
mq_bytes = (info->attr.mq_maxmsg * sizeof(struct msg_msg *) + /* Total amount of bytes accounted for the mqueue */
(info->attr.mq_maxmsg * info->attr.mq_msgsize)); mq_bytes = info->attr.mq_maxmsg * (sizeof(struct msg_msg *)
+ info->attr.mq_msgsize);
user = info->user; user = info->user;
if (user) { if (user) {
spin_lock(&mq_lock); spin_lock(&mq_lock);
@ -604,8 +604,8 @@ static int mq_attr_ok(struct ipc_namespace *ipc_ns, struct mq_attr *attr)
/* check for overflow */ /* check for overflow */
if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg) if (attr->mq_msgsize > ULONG_MAX/attr->mq_maxmsg)
return 0; return 0;
if ((unsigned long)(attr->mq_maxmsg * attr->mq_msgsize) + if ((unsigned long)(attr->mq_maxmsg * (attr->mq_msgsize
(attr->mq_maxmsg * sizeof (struct msg_msg *)) < + sizeof (struct msg_msg *))) <
(unsigned long)(attr->mq_maxmsg * attr->mq_msgsize)) (unsigned long)(attr->mq_maxmsg * attr->mq_msgsize))
return 0; return 0;
return 1; return 1;
@ -623,9 +623,10 @@ static struct file *do_create(struct ipc_namespace *ipc_ns, struct dentry *dir,
int ret; int ret;
if (attr) { if (attr) {
ret = -EINVAL; if (!mq_attr_ok(ipc_ns, attr)) {
if (!mq_attr_ok(ipc_ns, attr)) ret = -EINVAL;
goto out; goto out;
}
/* store for use during create */ /* store for use during create */
dentry->d_fsdata = attr; dentry->d_fsdata = attr;
} }
@ -659,24 +660,28 @@ out:
static struct file *do_open(struct ipc_namespace *ipc_ns, static struct file *do_open(struct ipc_namespace *ipc_ns,
struct dentry *dentry, int oflag) struct dentry *dentry, int oflag)
{ {
int ret;
const struct cred *cred = current_cred(); const struct cred *cred = current_cred();
static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE, static const int oflag2acc[O_ACCMODE] = { MAY_READ, MAY_WRITE,
MAY_READ | MAY_WRITE }; MAY_READ | MAY_WRITE };
if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) { if ((oflag & O_ACCMODE) == (O_RDWR | O_WRONLY)) {
dput(dentry); ret = -EINVAL;
mntput(ipc_ns->mq_mnt); goto err;
return ERR_PTR(-EINVAL);
} }
if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) { if (inode_permission(dentry->d_inode, oflag2acc[oflag & O_ACCMODE])) {
dput(dentry); ret = -EACCES;
mntput(ipc_ns->mq_mnt); goto err;
return ERR_PTR(-EACCES);
} }
return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred); return dentry_open(dentry, ipc_ns->mq_mnt, oflag, cred);
err:
dput(dentry);
mntput(ipc_ns->mq_mnt);
return ERR_PTR(ret);
} }
SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode, SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
@ -705,16 +710,17 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name)); dentry = lookup_one_len(name, ipc_ns->mq_mnt->mnt_root, strlen(name));
if (IS_ERR(dentry)) { if (IS_ERR(dentry)) {
error = PTR_ERR(dentry); error = PTR_ERR(dentry);
goto out_err; goto out_putfd;
} }
mntget(ipc_ns->mq_mnt); mntget(ipc_ns->mq_mnt);
if (oflag & O_CREAT) { if (oflag & O_CREAT) {
if (dentry->d_inode) { /* entry already exists */ if (dentry->d_inode) { /* entry already exists */
audit_inode(name, dentry); audit_inode(name, dentry);
error = -EEXIST; if (oflag & O_EXCL) {
if (oflag & O_EXCL) error = -EEXIST;
goto out; goto out;
}
filp = do_open(ipc_ns, dentry, oflag); filp = do_open(ipc_ns, dentry, oflag);
} else { } else {
filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root, filp = do_create(ipc_ns, ipc_ns->mq_mnt->mnt_root,
@ -722,9 +728,10 @@ SYSCALL_DEFINE4(mq_open, const char __user *, u_name, int, oflag, mode_t, mode,
u_attr ? &attr : NULL); u_attr ? &attr : NULL);
} }
} else { } else {
error = -ENOENT; if (!dentry->d_inode) {
if (!dentry->d_inode) error = -ENOENT;
goto out; goto out;
}
audit_inode(name, dentry); audit_inode(name, dentry);
filp = do_open(ipc_ns, dentry, oflag); filp = do_open(ipc_ns, dentry, oflag);
} }
@ -742,7 +749,6 @@ out:
mntput(ipc_ns->mq_mnt); mntput(ipc_ns->mq_mnt);
out_putfd: out_putfd:
put_unused_fd(fd); put_unused_fd(fd);
out_err:
fd = error; fd = error;
out_upsem: out_upsem:
mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex); mutex_unlock(&ipc_ns->mq_mnt->mnt_root->d_inode->i_mutex);
@ -872,19 +878,24 @@ SYSCALL_DEFINE5(mq_timedsend, mqd_t, mqdes, const char __user *, u_msg_ptr,
audit_mq_sendrecv(mqdes, msg_len, msg_prio, p); audit_mq_sendrecv(mqdes, msg_len, msg_prio, p);
timeout = prepare_timeout(p); timeout = prepare_timeout(p);
ret = -EBADF;
filp = fget(mqdes); filp = fget(mqdes);
if (unlikely(!filp)) if (unlikely(!filp)) {
ret = -EBADF;
goto out; goto out;
}
inode = filp->f_path.dentry->d_inode; inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations)) if (unlikely(filp->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput; goto out_fput;
}
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
audit_inode(NULL, filp->f_path.dentry); audit_inode(NULL, filp->f_path.dentry);
if (unlikely(!(filp->f_mode & FMODE_WRITE))) if (unlikely(!(filp->f_mode & FMODE_WRITE))) {
ret = -EBADF;
goto out_fput; goto out_fput;
}
if (unlikely(msg_len > info->attr.mq_msgsize)) { if (unlikely(msg_len > info->attr.mq_msgsize)) {
ret = -EMSGSIZE; ret = -EMSGSIZE;
@ -961,19 +972,24 @@ SYSCALL_DEFINE5(mq_timedreceive, mqd_t, mqdes, char __user *, u_msg_ptr,
audit_mq_sendrecv(mqdes, msg_len, 0, p); audit_mq_sendrecv(mqdes, msg_len, 0, p);
timeout = prepare_timeout(p); timeout = prepare_timeout(p);
ret = -EBADF;
filp = fget(mqdes); filp = fget(mqdes);
if (unlikely(!filp)) if (unlikely(!filp)) {
ret = -EBADF;
goto out; goto out;
}
inode = filp->f_path.dentry->d_inode; inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations)) if (unlikely(filp->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput; goto out_fput;
}
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
audit_inode(NULL, filp->f_path.dentry); audit_inode(NULL, filp->f_path.dentry);
if (unlikely(!(filp->f_mode & FMODE_READ))) if (unlikely(!(filp->f_mode & FMODE_READ))) {
ret = -EBADF;
goto out_fput; goto out_fput;
}
/* checks if buffer is big enough */ /* checks if buffer is big enough */
if (unlikely(msg_len < info->attr.mq_msgsize)) { if (unlikely(msg_len < info->attr.mq_msgsize)) {
@ -1063,13 +1079,14 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
/* create the notify skb */ /* create the notify skb */
nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL); nc = alloc_skb(NOTIFY_COOKIE_LEN, GFP_KERNEL);
ret = -ENOMEM; if (!nc) {
if (!nc) ret = -ENOMEM;
goto out; goto out;
ret = -EFAULT; }
if (copy_from_user(nc->data, if (copy_from_user(nc->data,
notification.sigev_value.sival_ptr, notification.sigev_value.sival_ptr,
NOTIFY_COOKIE_LEN)) { NOTIFY_COOKIE_LEN)) {
ret = -EFAULT;
goto out; goto out;
} }
@ -1078,9 +1095,10 @@ SYSCALL_DEFINE2(mq_notify, mqd_t, mqdes,
/* and attach it to the socket */ /* and attach it to the socket */
retry: retry:
filp = fget(notification.sigev_signo); filp = fget(notification.sigev_signo);
ret = -EBADF; if (!filp) {
if (!filp) ret = -EBADF;
goto out; goto out;
}
sock = netlink_getsockbyfilp(filp); sock = netlink_getsockbyfilp(filp);
fput(filp); fput(filp);
if (IS_ERR(sock)) { if (IS_ERR(sock)) {
@ -1092,7 +1110,7 @@ retry:
timeo = MAX_SCHEDULE_TIMEOUT; timeo = MAX_SCHEDULE_TIMEOUT;
ret = netlink_attachskb(sock, nc, &timeo, NULL); ret = netlink_attachskb(sock, nc, &timeo, NULL);
if (ret == 1) if (ret == 1)
goto retry; goto retry;
if (ret) { if (ret) {
sock = NULL; sock = NULL;
nc = NULL; nc = NULL;
@ -1101,14 +1119,17 @@ retry:
} }
} }
ret = -EBADF;
filp = fget(mqdes); filp = fget(mqdes);
if (!filp) if (!filp) {
ret = -EBADF;
goto out; goto out;
}
inode = filp->f_path.dentry->d_inode; inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations)) if (unlikely(filp->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput; goto out_fput;
}
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
ret = 0; ret = 0;
@ -1171,14 +1192,17 @@ SYSCALL_DEFINE3(mq_getsetattr, mqd_t, mqdes,
return -EINVAL; return -EINVAL;
} }
ret = -EBADF;
filp = fget(mqdes); filp = fget(mqdes);
if (!filp) if (!filp) {
ret = -EBADF;
goto out; goto out;
}
inode = filp->f_path.dentry->d_inode; inode = filp->f_path.dentry->d_inode;
if (unlikely(filp->f_op != &mqueue_file_operations)) if (unlikely(filp->f_op != &mqueue_file_operations)) {
ret = -EBADF;
goto out_fput; goto out_fput;
}
info = MQUEUE_I(inode); info = MQUEUE_I(inode);
spin_lock(&info->lock); spin_lock(&info->lock);
@ -1272,7 +1296,7 @@ static int __init init_mqueue_fs(void)
if (mqueue_inode_cachep == NULL) if (mqueue_inode_cachep == NULL)
return -ENOMEM; return -ENOMEM;
/* ignore failues - they are not fatal */ /* ignore failures - they are not fatal */
mq_sysctl_table = mq_register_sysctl_table(); mq_sysctl_table = mq_register_sysctl_table();
error = register_filesystem(&mqueue_fs_type); error = register_filesystem(&mqueue_fs_type);

View file

@ -548,6 +548,11 @@ int audit_remove_tree_rule(struct audit_krule *rule)
return 0; return 0;
} }
static int compare_root(struct vfsmount *mnt, void *arg)
{
return mnt->mnt_root->d_inode == arg;
}
void audit_trim_trees(void) void audit_trim_trees(void)
{ {
struct list_head cursor; struct list_head cursor;
@ -559,7 +564,6 @@ void audit_trim_trees(void)
struct path path; struct path path;
struct vfsmount *root_mnt; struct vfsmount *root_mnt;
struct node *node; struct node *node;
struct list_head list;
int err; int err;
tree = container_of(cursor.next, struct audit_tree, list); tree = container_of(cursor.next, struct audit_tree, list);
@ -577,24 +581,16 @@ void audit_trim_trees(void)
if (!root_mnt) if (!root_mnt)
goto skip_it; goto skip_it;
list_add_tail(&list, &root_mnt->mnt_list);
spin_lock(&hash_lock); spin_lock(&hash_lock);
list_for_each_entry(node, &tree->chunks, list) { list_for_each_entry(node, &tree->chunks, list) {
struct audit_chunk *chunk = find_chunk(node); struct inode *inode = find_chunk(node)->watch.inode;
struct inode *inode = chunk->watch.inode;
struct vfsmount *mnt;
node->index |= 1U<<31; node->index |= 1U<<31;
list_for_each_entry(mnt, &list, mnt_list) { if (iterate_mounts(compare_root, inode, root_mnt))
if (mnt->mnt_root->d_inode == inode) { node->index &= ~(1U<<31);
node->index &= ~(1U<<31);
break;
}
}
} }
spin_unlock(&hash_lock); spin_unlock(&hash_lock);
trim_marked(tree); trim_marked(tree);
put_tree(tree); put_tree(tree);
list_del_init(&list);
drop_collected_mounts(root_mnt); drop_collected_mounts(root_mnt);
skip_it: skip_it:
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
@ -603,22 +599,6 @@ skip_it:
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
} }
static int is_under(struct vfsmount *mnt, struct dentry *dentry,
struct path *path)
{
if (mnt != path->mnt) {
for (;;) {
if (mnt->mnt_parent == mnt)
return 0;
if (mnt->mnt_parent == path->mnt)
break;
mnt = mnt->mnt_parent;
}
dentry = mnt->mnt_mountpoint;
}
return is_subdir(dentry, path->dentry);
}
int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op) int audit_make_tree(struct audit_krule *rule, char *pathname, u32 op)
{ {
@ -638,13 +618,17 @@ void audit_put_tree(struct audit_tree *tree)
put_tree(tree); put_tree(tree);
} }
static int tag_mount(struct vfsmount *mnt, void *arg)
{
return tag_chunk(mnt->mnt_root->d_inode, arg);
}
/* called with audit_filter_mutex */ /* called with audit_filter_mutex */
int audit_add_tree_rule(struct audit_krule *rule) int audit_add_tree_rule(struct audit_krule *rule)
{ {
struct audit_tree *seed = rule->tree, *tree; struct audit_tree *seed = rule->tree, *tree;
struct path path; struct path path;
struct vfsmount *mnt, *p; struct vfsmount *mnt;
struct list_head list;
int err; int err;
list_for_each_entry(tree, &tree_list, list) { list_for_each_entry(tree, &tree_list, list) {
@ -670,16 +654,9 @@ int audit_add_tree_rule(struct audit_krule *rule)
err = -ENOMEM; err = -ENOMEM;
goto Err; goto Err;
} }
list_add_tail(&list, &mnt->mnt_list);
get_tree(tree); get_tree(tree);
list_for_each_entry(p, &list, mnt_list) { err = iterate_mounts(tag_mount, tree, mnt);
err = tag_chunk(p->mnt_root->d_inode, tree);
if (err)
break;
}
list_del(&list);
drop_collected_mounts(mnt); drop_collected_mounts(mnt);
if (!err) { if (!err) {
@ -714,31 +691,23 @@ int audit_tag_tree(char *old, char *new)
{ {
struct list_head cursor, barrier; struct list_head cursor, barrier;
int failed = 0; int failed = 0;
struct path path; struct path path1, path2;
struct vfsmount *tagged; struct vfsmount *tagged;
struct list_head list;
struct vfsmount *mnt;
struct dentry *dentry;
int err; int err;
err = kern_path(new, 0, &path); err = kern_path(new, 0, &path2);
if (err) if (err)
return err; return err;
tagged = collect_mounts(&path); tagged = collect_mounts(&path2);
path_put(&path); path_put(&path2);
if (!tagged) if (!tagged)
return -ENOMEM; return -ENOMEM;
err = kern_path(old, 0, &path); err = kern_path(old, 0, &path1);
if (err) { if (err) {
drop_collected_mounts(tagged); drop_collected_mounts(tagged);
return err; return err;
} }
mnt = mntget(path.mnt);
dentry = dget(path.dentry);
path_put(&path);
list_add_tail(&list, &tagged->mnt_list);
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
list_add(&barrier, &tree_list); list_add(&barrier, &tree_list);
@ -746,7 +715,7 @@ int audit_tag_tree(char *old, char *new)
while (cursor.next != &tree_list) { while (cursor.next != &tree_list) {
struct audit_tree *tree; struct audit_tree *tree;
struct vfsmount *p; int good_one = 0;
tree = container_of(cursor.next, struct audit_tree, list); tree = container_of(cursor.next, struct audit_tree, list);
get_tree(tree); get_tree(tree);
@ -754,30 +723,19 @@ int audit_tag_tree(char *old, char *new)
list_add(&cursor, &tree->list); list_add(&cursor, &tree->list);
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
err = kern_path(tree->pathname, 0, &path); err = kern_path(tree->pathname, 0, &path2);
if (err) { if (!err) {
good_one = path_is_under(&path1, &path2);
path_put(&path2);
}
if (!good_one) {
put_tree(tree); put_tree(tree);
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
continue; continue;
} }
spin_lock(&vfsmount_lock); failed = iterate_mounts(tag_mount, tree, tagged);
if (!is_under(mnt, dentry, &path)) {
spin_unlock(&vfsmount_lock);
path_put(&path);
put_tree(tree);
mutex_lock(&audit_filter_mutex);
continue;
}
spin_unlock(&vfsmount_lock);
path_put(&path);
list_for_each_entry(p, &list, mnt_list) {
failed = tag_chunk(p->mnt_root->d_inode, tree);
if (failed)
break;
}
if (failed) { if (failed) {
put_tree(tree); put_tree(tree);
mutex_lock(&audit_filter_mutex); mutex_lock(&audit_filter_mutex);
@ -818,10 +776,8 @@ int audit_tag_tree(char *old, char *new)
} }
list_del(&barrier); list_del(&barrier);
list_del(&cursor); list_del(&cursor);
list_del(&list);
mutex_unlock(&audit_filter_mutex); mutex_unlock(&audit_filter_mutex);
dput(dentry); path_put(&path1);
mntput(mnt);
drop_collected_mounts(tagged); drop_collected_mounts(tagged);
return failed; return failed;
} }

View file

@ -1988,7 +1988,6 @@ void __audit_inode(const char *name, const struct dentry *dentry)
/** /**
* audit_inode_child - collect inode info for created/removed objects * audit_inode_child - collect inode info for created/removed objects
* @dname: inode's dentry name
* @dentry: dentry being audited * @dentry: dentry being audited
* @parent: inode of dentry parent * @parent: inode of dentry parent
* *
@ -2000,13 +1999,14 @@ void __audit_inode(const char *name, const struct dentry *dentry)
* must be hooked prior, in order to capture the target inode during * must be hooked prior, in order to capture the target inode during
* unsuccessful attempts. * unsuccessful attempts.
*/ */
void __audit_inode_child(const char *dname, const struct dentry *dentry, void __audit_inode_child(const struct dentry *dentry,
const struct inode *parent) const struct inode *parent)
{ {
int idx; int idx;
struct audit_context *context = current->audit_context; struct audit_context *context = current->audit_context;
const char *found_parent = NULL, *found_child = NULL; const char *found_parent = NULL, *found_child = NULL;
const struct inode *inode = dentry->d_inode; const struct inode *inode = dentry->d_inode;
const char *dname = dentry->d_name.name;
int dirlen = 0; int dirlen = 0;
if (!context->in_syscall) if (!context->in_syscall)
@ -2014,9 +2014,6 @@ void __audit_inode_child(const char *dname, const struct dentry *dentry,
if (inode) if (inode)
handle_one(inode); handle_one(inode);
/* determine matching parent */
if (!dname)
goto add_names;
/* parent is more likely, look for it first */ /* parent is more likely, look for it first */
for (idx = 0; idx < context->name_count; idx++) { for (idx = 0; idx < context->name_count; idx++) {

View file

@ -1331,7 +1331,7 @@ static ssize_t binary_sysctl(const int *name, int nlen,
ssize_t result; ssize_t result;
char *pathname; char *pathname;
int flags; int flags;
int acc_mode, fmode; int acc_mode;
pathname = sysctl_getname(name, nlen, &table); pathname = sysctl_getname(name, nlen, &table);
result = PTR_ERR(pathname); result = PTR_ERR(pathname);
@ -1342,15 +1342,12 @@ static ssize_t binary_sysctl(const int *name, int nlen,
if (oldval && oldlen && newval && newlen) { if (oldval && oldlen && newval && newlen) {
flags = O_RDWR; flags = O_RDWR;
acc_mode = MAY_READ | MAY_WRITE; acc_mode = MAY_READ | MAY_WRITE;
fmode = FMODE_READ | FMODE_WRITE;
} else if (newval && newlen) { } else if (newval && newlen) {
flags = O_WRONLY; flags = O_WRONLY;
acc_mode = MAY_WRITE; acc_mode = MAY_WRITE;
fmode = FMODE_WRITE;
} else if (oldval && oldlen) { } else if (oldval && oldlen) {
flags = O_RDONLY; flags = O_RDONLY;
acc_mode = MAY_READ; acc_mode = MAY_READ;
fmode = FMODE_READ;
} else { } else {
result = 0; result = 0;
goto out_putname; goto out_putname;
@ -1361,7 +1358,7 @@ static ssize_t binary_sysctl(const int *name, int nlen,
if (result) if (result)
goto out_putname; goto out_putname;
result = may_open(&nd.path, acc_mode, fmode); result = may_open(&nd.path, acc_mode, flags);
if (result) if (result)
goto out_putpath; goto out_putpath;

View file

@ -1117,7 +1117,7 @@ readpage:
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
if (page->mapping == NULL) { if (page->mapping == NULL) {
/* /*
* invalidate_inode_pages got it * invalidate_mapping_pages got it
*/ */
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);

View file

@ -999,19 +999,14 @@ rpc_fill_super(struct super_block *sb, void *data, int silent)
inode = rpc_get_inode(sb, S_IFDIR | 0755); inode = rpc_get_inode(sb, S_IFDIR | 0755);
if (!inode) if (!inode)
return -ENOMEM; return -ENOMEM;
root = d_alloc_root(inode); sb->s_root = root = d_alloc_root(inode);
if (!root) { if (!root) {
iput(inode); iput(inode);
return -ENOMEM; return -ENOMEM;
} }
if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL)) if (rpc_populate(root, files, RPCAUTH_lockd, RPCAUTH_RootEOF, NULL))
goto out; return -ENOMEM;
sb->s_root = root;
return 0; return 0;
out:
d_genocide(root);
dput(root);
return -ENOMEM;
} }
static int static int

View file

@ -387,7 +387,7 @@ static int smack_sb_umount(struct vfsmount *mnt, int flags)
struct smk_audit_info ad; struct smk_audit_info ad;
smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS); smk_ad_init(&ad, __func__, LSM_AUDIT_DATA_FS);
smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_mountpoint); smk_ad_setfield_u_fs_path_dentry(&ad, mnt->mnt_root);
smk_ad_setfield_u_fs_path_mnt(&ad, mnt); smk_ad_setfield_u_fs_path_mnt(&ad, mnt);
sbp = mnt->mnt_sb->s_security; sbp = mnt->mnt_sb->s_security;

View file

@ -88,29 +88,14 @@ int tomoyo_realpath_from_path2(struct path *path, char *newname,
sp = dentry->d_op->d_dname(dentry, newname + offset, sp = dentry->d_op->d_dname(dentry, newname + offset,
newname_len - offset); newname_len - offset);
} else { } else {
/* Taken from d_namespace_path(). */ struct path ns_root = {.mnt = NULL, .dentry = NULL};
struct path root;
struct path ns_root = { };
struct path tmp;
read_lock(&current->fs->lock);
root = current->fs->root;
path_get(&root);
read_unlock(&current->fs->lock);
spin_lock(&vfsmount_lock);
if (root.mnt && root.mnt->mnt_ns)
ns_root.mnt = mntget(root.mnt->mnt_ns->root);
if (ns_root.mnt)
ns_root.dentry = dget(ns_root.mnt->mnt_root);
spin_unlock(&vfsmount_lock);
spin_lock(&dcache_lock); spin_lock(&dcache_lock);
tmp = ns_root; /* go to whatever namespace root we are under */
sp = __d_path(path, &tmp, newname, newname_len); sp = __d_path(path, &ns_root, newname, newname_len);
spin_unlock(&dcache_lock); spin_unlock(&dcache_lock);
path_put(&root);
path_put(&ns_root);
/* Prepend "/proc" prefix if using internal proc vfs mount. */ /* Prepend "/proc" prefix if using internal proc vfs mount. */
if (!IS_ERR(sp) && (path->mnt->mnt_parent == path->mnt) && if (!IS_ERR(sp) && (path->mnt->mnt_flags & MNT_INTERNAL) &&
(path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) { (path->mnt->mnt_sb->s_magic == PROC_SUPER_MAGIC)) {
sp -= 5; sp -= 5;
if (sp >= newname) if (sp >= newname)