aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/Kconfig.binfmt2
-rw-r--r--fs/adfs/dir_f.c4
-rw-r--r--fs/affs/file.c21
-rw-r--r--fs/affs/super.c3
-rw-r--r--fs/afs/afs_cm.h3
-rw-r--r--fs/afs/cell.c2
-rw-r--r--fs/afs/cmservice.c133
-rw-r--r--fs/afs/proc.c33
-rw-r--r--fs/aio.c74
-rw-r--r--fs/autofs4/root.c2
-rw-r--r--fs/befs/linuxvfs.c6
-rw-r--r--fs/binfmt_aout.c12
-rw-r--r--fs/binfmt_elf.c30
-rw-r--r--fs/binfmt_elf_fdpic.c14
-rw-r--r--fs/binfmt_em86.c2
-rw-r--r--fs/binfmt_flat.c9
-rw-r--r--fs/binfmt_misc.c6
-rw-r--r--fs/binfmt_script.c2
-rw-r--r--fs/buffer.c22
-rw-r--r--fs/char_dev.c1
-rw-r--r--fs/cifs/cifs_debug.c4
-rw-r--r--fs/coda/coda_linux.c2
-rw-r--r--fs/coda/dir.c6
-rw-r--r--fs/drop_caches.c14
-rw-r--r--fs/ecryptfs/Makefile2
-rw-r--r--fs/ecryptfs/crypto.c33
-rw-r--r--fs/ecryptfs/ecryptfs_kernel.h102
-rw-r--r--fs/ecryptfs/file.c2
-rw-r--r--fs/ecryptfs/inode.c6
-rw-r--r--fs/ecryptfs/keystore.c89
-rw-r--r--fs/ecryptfs/main.c2
-rw-r--r--fs/ecryptfs/messaging.c524
-rw-r--r--fs/ecryptfs/miscdev.c598
-rw-r--r--fs/ecryptfs/mmap.c18
-rw-r--r--fs/ecryptfs/netlink.c33
-rw-r--r--fs/ecryptfs/read_write.c16
-rw-r--r--fs/eventpoll.c27
-rw-r--r--fs/exec.c6
-rw-r--r--fs/ext4/mballoc.c22
-rw-r--r--fs/fat/inode.c8
-rw-r--r--fs/freevxfs/vxfs_extern.h5
-rw-r--r--fs/freevxfs/vxfs_immed.c1
-rw-r--r--fs/freevxfs/vxfs_inode.c5
-rw-r--r--fs/fs-writeback.c78
-rw-r--r--fs/hfs/super.c6
-rw-r--r--fs/hfsplus/hfsplus_fs.h4
-rw-r--r--fs/hfsplus/inode.c3
-rw-r--r--fs/hfsplus/options.c3
-rw-r--r--fs/hfsplus/wrapper.c2
-rw-r--r--fs/inode.c6
-rw-r--r--fs/inotify_user.c2
-rw-r--r--fs/ioctl.c4
-rw-r--r--fs/isofs/isofs.h12
-rw-r--r--fs/jbd2/journal.c17
-rw-r--r--fs/jfs/jfs_debug.c4
-rw-r--r--fs/namei.c9
-rw-r--r--fs/namespace.c13
-rw-r--r--fs/ncpfs/ncplib_kernel.c39
-rw-r--r--fs/nfs/client.c20
-rw-r--r--fs/nfsd/nfsctl.c4
-rw-r--r--fs/ntfs/mft.c6
-rw-r--r--fs/proc/base.c113
-rw-r--r--fs/proc/generic.c132
-rw-r--r--fs/proc/inode.c69
-rw-r--r--fs/proc/internal.h4
-rw-r--r--fs/proc/nommu.c2
-rw-r--r--fs/proc/proc_misc.c66
-rw-r--r--fs/proc/proc_sysctl.c52
-rw-r--r--fs/proc/proc_tty.c81
-rw-r--r--fs/proc/root.c14
-rw-r--r--fs/proc/task_mmu.c34
-rw-r--r--fs/proc/task_nommu.c34
-rw-r--r--fs/ramfs/file-mmu.c3
-rw-r--r--fs/ramfs/internal.h1
-rw-r--r--fs/reiserfs/procfs.c9
-rw-r--r--fs/super.c2
-rw-r--r--fs/sync.c2
-rw-r--r--fs/timerfd.c1
-rw-r--r--fs/xattr.c41
79 files changed, 1842 insertions, 956 deletions
diff --git a/fs/Kconfig.binfmt b/fs/Kconfig.binfmt
index 853845abcca6..55e8ee1900a5 100644
--- a/fs/Kconfig.binfmt
+++ b/fs/Kconfig.binfmt
@@ -41,7 +41,7 @@ config BINFMT_ELF_FDPIC
It is also possible to run FDPIC ELF binaries on MMU linux also.
config BINFMT_FLAT
- tristate "Kernel support for flat binaries"
+ bool "Kernel support for flat binaries"
depends on !MMU
help
Support uClinux FLAT format binaries.
diff --git a/fs/adfs/dir_f.c b/fs/adfs/dir_f.c
index b9b2b27b68c3..ea7df2146921 100644
--- a/fs/adfs/dir_f.c
+++ b/fs/adfs/dir_f.c
@@ -122,9 +122,9 @@ adfs_dir_checkbyte(const struct adfs_dir *dir)
ptr.ptr8 = bufoff(bh, i);
end.ptr8 = ptr.ptr8 + last - i;
- do
+ do {
dircheck = *ptr.ptr8++ ^ ror13(dircheck);
- while (ptr.ptr8 < end.ptr8);
+ } while (ptr.ptr8 < end.ptr8);
}
/*
diff --git a/fs/affs/file.c b/fs/affs/file.c
index 6e0c9399200e..e87ede608f77 100644
--- a/fs/affs/file.c
+++ b/fs/affs/file.c
@@ -325,8 +325,7 @@ affs_get_block(struct inode *inode, sector_t block, struct buffer_head *bh_resul
pr_debug("AFFS: get_block(%u, %lu)\n", (u32)inode->i_ino, (unsigned long)block);
- if (block > (sector_t)0x7fffffffUL)
- BUG();
+ BUG_ON(block > (sector_t)0x7fffffffUL);
if (block >= AFFS_I(inode)->i_blkcnt) {
if (block > AFFS_I(inode)->i_blkcnt || !create)
@@ -493,8 +492,7 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
u32 tmp;
pr_debug("AFFS: read_page(%u, %ld, %d, %d)\n", (u32)inode->i_ino, page->index, from, to);
- if (from > to || to > PAGE_CACHE_SIZE)
- BUG();
+ BUG_ON(from > to || to > PAGE_CACHE_SIZE);
kmap(page);
data = page_address(page);
bsize = AFFS_SB(sb)->s_data_blksize;
@@ -507,8 +505,7 @@ affs_do_readpage_ofs(struct file *file, struct page *page, unsigned from, unsign
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, to - from);
- if (from + tmp > to || tmp > bsize)
- BUG();
+ BUG_ON(from + tmp > to || tmp > bsize);
memcpy(data + from, AFFS_DATA(bh) + boff, tmp);
affs_brelse(bh);
bidx++;
@@ -540,8 +537,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, newsize - size);
- if (boff + tmp > bsize || tmp > bsize)
- BUG();
+ BUG_ON(boff + tmp > bsize || tmp > bsize);
memset(AFFS_DATA(bh) + boff, 0, tmp);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
affs_fix_checksum(sb, bh);
@@ -560,8 +556,7 @@ affs_extent_file_ofs(struct inode *inode, u32 newsize)
if (IS_ERR(bh))
goto out;
tmp = min(bsize, newsize - size);
- if (tmp > bsize)
- BUG();
+ BUG_ON(tmp > bsize);
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
AFFS_DATA_HEAD(bh)->key = cpu_to_be32(inode->i_ino);
AFFS_DATA_HEAD(bh)->sequence = cpu_to_be32(bidx);
@@ -683,8 +678,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
if (IS_ERR(bh))
return PTR_ERR(bh);
tmp = min(bsize - boff, to - from);
- if (boff + tmp > bsize || tmp > bsize)
- BUG();
+ BUG_ON(boff + tmp > bsize || tmp > bsize);
memcpy(AFFS_DATA(bh) + boff, data + from, tmp);
AFFS_DATA_HEAD(bh)->size = cpu_to_be32(be32_to_cpu(AFFS_DATA_HEAD(bh)->size) + tmp);
affs_fix_checksum(sb, bh);
@@ -732,8 +726,7 @@ static int affs_write_end_ofs(struct file *file, struct address_space *mapping,
if (IS_ERR(bh))
goto out;
tmp = min(bsize, to - from);
- if (tmp > bsize)
- BUG();
+ BUG_ON(tmp > bsize);
memcpy(AFFS_DATA(bh), data + from, tmp);
if (buffer_new(bh)) {
AFFS_DATA_HEAD(bh)->ptype = cpu_to_be32(T_DATA);
diff --git a/fs/affs/super.c b/fs/affs/super.c
index d2dc047cb479..01d25d532541 100644
--- a/fs/affs/super.c
+++ b/fs/affs/super.c
@@ -199,7 +199,6 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
case Opt_prefix:
/* Free any previous prefix */
kfree(*prefix);
- *prefix = NULL;
*prefix = match_strdup(&args[0]);
if (!*prefix)
return 0;
@@ -233,6 +232,8 @@ parse_options(char *options, uid_t *uid, gid_t *gid, int *mode, int *reserved, s
break;
case Opt_volume: {
char *vol = match_strdup(&args[0]);
+ if (!vol)
+ return 0;
strlcpy(volume, vol, 32);
kfree(vol);
break;
diff --git a/fs/afs/afs_cm.h b/fs/afs/afs_cm.h
index 7b4d4fab4c80..255f5dd6040c 100644
--- a/fs/afs/afs_cm.h
+++ b/fs/afs/afs_cm.h
@@ -24,7 +24,8 @@ enum AFS_CM_Operations {
CBGetXStatsVersion = 209, /* get version of extended statistics */
CBGetXStats = 210, /* get contents of extended statistics data */
CBInitCallBackState3 = 213, /* initialise callback state, version 3 */
- CBGetCapabilities = 65538, /* get client capabilities */
+ CBProbeUuid = 214, /* check the client hasn't rebooted */
+ CBTellMeAboutYourself = 65538, /* get client capabilities */
};
#define AFS_CAP_ERROR_TRANSLATION 0x1
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 584bb0f9c36a..5e1df14e16b1 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -20,7 +20,7 @@
DECLARE_RWSEM(afs_proc_cells_sem);
LIST_HEAD(afs_proc_cells);
-static struct list_head afs_cells = LIST_HEAD_INIT(afs_cells);
+static LIST_HEAD(afs_cells);
static DEFINE_RWLOCK(afs_cells_lock);
static DECLARE_RWSEM(afs_cells_sem); /* add/remove serialisation */
static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index 47b71c8947f9..eb765489164f 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -26,8 +26,9 @@ static int afs_deliver_cb_init_call_back_state3(struct afs_call *,
struct sk_buff *, bool);
static int afs_deliver_cb_probe(struct afs_call *, struct sk_buff *, bool);
static int afs_deliver_cb_callback(struct afs_call *, struct sk_buff *, bool);
-static int afs_deliver_cb_get_capabilities(struct afs_call *, struct sk_buff *,
- bool);
+static int afs_deliver_cb_probe_uuid(struct afs_call *, struct sk_buff *, bool);
+static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *,
+ struct sk_buff *, bool);
static void afs_cm_destructor(struct afs_call *);
/*
@@ -71,11 +72,21 @@ static const struct afs_call_type afs_SRXCBProbe = {
};
/*
- * CB.GetCapabilities operation type
+ * CB.ProbeUuid operation type
*/
-static const struct afs_call_type afs_SRXCBGetCapabilites = {
- .name = "CB.GetCapabilities",
- .deliver = afs_deliver_cb_get_capabilities,
+static const struct afs_call_type afs_SRXCBProbeUuid = {
+ .name = "CB.ProbeUuid",
+ .deliver = afs_deliver_cb_probe_uuid,
+ .abort_to_error = afs_abort_to_error,
+ .destructor = afs_cm_destructor,
+};
+
+/*
+ * CB.TellMeAboutYourself operation type
+ */
+static const struct afs_call_type afs_SRXCBTellMeAboutYourself = {
+ .name = "CB.TellMeAboutYourself",
+ .deliver = afs_deliver_cb_tell_me_about_yourself,
.abort_to_error = afs_abort_to_error,
.destructor = afs_cm_destructor,
};
@@ -103,8 +114,8 @@ bool afs_cm_incoming_call(struct afs_call *call)
case CBProbe:
call->type = &afs_SRXCBProbe;
return true;
- case CBGetCapabilities:
- call->type = &afs_SRXCBGetCapabilites;
+ case CBTellMeAboutYourself:
+ call->type = &afs_SRXCBTellMeAboutYourself;
return true;
default:
return false;
@@ -393,9 +404,105 @@ static int afs_deliver_cb_probe(struct afs_call *call, struct sk_buff *skb,
}
/*
+ * allow the fileserver to quickly find out if the fileserver has been rebooted
+ */
+static void SRXAFSCB_ProbeUuid(struct work_struct *work)
+{
+ struct afs_call *call = container_of(work, struct afs_call, work);
+ struct afs_uuid *r = call->request;
+
+ struct {
+ __be32 match;
+ } reply;
+
+ _enter("");
+
+
+ if (memcmp(r, &afs_uuid, sizeof(afs_uuid)) == 0)
+ reply.match = htonl(0);
+ else
+ reply.match = htonl(1);
+
+ afs_send_simple_reply(call, &reply, sizeof(reply));
+ _leave("");
+}
+
+/*
+ * deliver request data to a CB.ProbeUuid call
+ */
+static int afs_deliver_cb_probe_uuid(struct afs_call *call, struct sk_buff *skb,
+ bool last)
+{
+ struct afs_uuid *r;
+ unsigned loop;
+ __be32 *b;
+ int ret;
+
+ _enter("{%u},{%u},%d", call->unmarshall, skb->len, last);
+
+ if (skb->len > 0)
+ return -EBADMSG;
+ if (!last)
+ return 0;
+
+ switch (call->unmarshall) {
+ case 0:
+ call->offset = 0;
+ call->buffer = kmalloc(11 * sizeof(__be32), GFP_KERNEL);
+ if (!call->buffer)
+ return -ENOMEM;
+ call->unmarshall++;
+
+ case 1:
+ _debug("extract UUID");
+ ret = afs_extract_data(call, skb, last, call->buffer,
+ 11 * sizeof(__be32));
+ switch (ret) {
+ case 0: break;
+ case -EAGAIN: return 0;
+ default: return ret;
+ }
+
+ _debug("unmarshall UUID");
+ call->request = kmalloc(sizeof(struct afs_uuid), GFP_KERNEL);
+ if (!call->request)
+ return -ENOMEM;
+
+ b = call->buffer;
+ r = call->request;
+ r->time_low = ntohl(b[0]);
+ r->time_mid = ntohl(b[1]);
+ r->time_hi_and_version = ntohl(b[2]);
+ r->clock_seq_hi_and_reserved = ntohl(b[3]);
+ r->clock_seq_low = ntohl(b[4]);
+
+ for (loop = 0; loop < 6; loop++)
+ r->node[loop] = ntohl(b[loop + 5]);
+
+ call->offset = 0;
+ call->unmarshall++;
+
+ case 2:
+ _debug("trailer");
+ if (skb->len != 0)
+ return -EBADMSG;
+ break;
+ }
+
+ if (!last)
+ return 0;
+
+ call->state = AFS_CALL_REPLYING;
+
+ INIT_WORK(&call->work, SRXAFSCB_ProbeUuid);
+ schedule_work(&call->work);
+ return 0;
+}
+
+/*
* allow the fileserver to ask about the cache manager's capabilities
*/
-static void SRXAFSCB_GetCapabilities(struct work_struct *work)
+static void SRXAFSCB_TellMeAboutYourself(struct work_struct *work)
{
struct afs_interface *ifs;
struct afs_call *call = container_of(work, struct afs_call, work);
@@ -456,10 +563,10 @@ static void SRXAFSCB_GetCapabilities(struct work_struct *work)
}
/*
- * deliver request data to a CB.GetCapabilities call
+ * deliver request data to a CB.TellMeAboutYourself call
*/
-static int afs_deliver_cb_get_capabilities(struct afs_call *call,
- struct sk_buff *skb, bool last)
+static int afs_deliver_cb_tell_me_about_yourself(struct afs_call *call,
+ struct sk_buff *skb, bool last)
{
_enter(",{%u},%d", skb->len, last);
@@ -471,7 +578,7 @@ static int afs_deliver_cb_get_capabilities(struct afs_call *call,
/* no unmarshalling required */
call->state = AFS_CALL_REPLYING;
- INIT_WORK(&call->work, SRXAFSCB_GetCapabilities);
+ INIT_WORK(&call->work, SRXAFSCB_TellMeAboutYourself);
schedule_work(&call->work);
return 0;
}
diff --git a/fs/afs/proc.c b/fs/afs/proc.c
index 846c7615ac9e..9f7d1ae70269 100644
--- a/fs/afs/proc.c
+++ b/fs/afs/proc.c
@@ -41,6 +41,7 @@ static const struct file_operations afs_proc_cells_fops = {
.write = afs_proc_cells_write,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_rootcell_open(struct inode *inode, struct file *file);
@@ -56,7 +57,8 @@ static const struct file_operations afs_proc_rootcell_fops = {
.read = afs_proc_rootcell_read,
.write = afs_proc_rootcell_write,
.llseek = no_llseek,
- .release = afs_proc_rootcell_release
+ .release = afs_proc_rootcell_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_cell_volumes_open(struct inode *inode, struct file *file);
@@ -80,6 +82,7 @@ static const struct file_operations afs_proc_cell_volumes_fops = {
.read = seq_read,
.llseek = seq_lseek,
.release = afs_proc_cell_volumes_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_cell_vlservers_open(struct inode *inode,
@@ -104,6 +107,7 @@ static const struct file_operations afs_proc_cell_vlservers_fops = {
.read = seq_read,
.llseek = seq_lseek,
.release = afs_proc_cell_vlservers_release,
+ .owner = THIS_MODULE,
};
static int afs_proc_cell_servers_open(struct inode *inode, struct file *file);
@@ -127,6 +131,7 @@ static const struct file_operations afs_proc_cell_servers_fops = {
.read = seq_read,
.llseek = seq_lseek,
.release = afs_proc_cell_servers_release,
+ .owner = THIS_MODULE,
};
/*
@@ -143,17 +148,13 @@ int afs_proc_init(void)
goto error_dir;
proc_afs->owner = THIS_MODULE;
- p = create_proc_entry("cells", 0, proc_afs);
+ p = proc_create("cells", 0, proc_afs, &afs_proc_cells_fops);
if (!p)
goto error_cells;
- p->proc_fops = &afs_proc_cells_fops;
- p->owner = THIS_MODULE;
- p = create_proc_entry("rootcell", 0, proc_afs);
+ p = proc_create("rootcell", 0, proc_afs, &afs_proc_rootcell_fops);
if (!p)
goto error_rootcell;
- p->proc_fops = &afs_proc_rootcell_fops;
- p->owner = THIS_MODULE;
_leave(" = 0");
return 0;
@@ -395,26 +396,20 @@ int afs_proc_cell_setup(struct afs_cell *cell)
if (!cell->proc_dir)
goto error_dir;
- p = create_proc_entry("servers", 0, cell->proc_dir);
+ p = proc_create_data("servers", 0, cell->proc_dir,
+ &afs_proc_cell_servers_fops, cell);
if (!p)
goto error_servers;
- p->proc_fops = &afs_proc_cell_servers_fops;
- p->owner = THIS_MODULE;
- p->data = cell;
- p = create_proc_entry("vlservers", 0, cell->proc_dir);
+ p = proc_create_data("vlservers", 0, cell->proc_dir,
+ &afs_proc_cell_vlservers_fops, cell);
if (!p)
goto error_vlservers;
- p->proc_fops = &afs_proc_cell_vlservers_fops;
- p->owner = THIS_MODULE;
- p->data = cell;
- p = create_proc_entry("volumes", 0, cell->proc_dir);
+ p = proc_create_data("volumes", 0, cell->proc_dir,
+ &afs_proc_cell_volumes_fops, cell);
if (!p)
goto error_volumes;
- p->proc_fops = &afs_proc_cell_volumes_fops;
- p->owner = THIS_MODULE;
- p->data = cell;
_leave(" = 0");
return 0;
diff --git a/fs/aio.c b/fs/aio.c
index ae94e1dea266..99c2352906a0 100644
--- a/fs/aio.c
+++ b/fs/aio.c
@@ -191,6 +191,43 @@ static int aio_setup_ring(struct kioctx *ctx)
kunmap_atomic((void *)((unsigned long)__event & PAGE_MASK), km); \
} while(0)
+
+/* __put_ioctx
+ * Called when the last user of an aio context has gone away,
+ * and the struct needs to be freed.
+ */
+static void __put_ioctx(struct kioctx *ctx)
+{
+ unsigned nr_events = ctx->max_reqs;
+
+ BUG_ON(ctx->reqs_active);
+
+ cancel_delayed_work(&ctx->wq);
+ cancel_work_sync(&ctx->wq.work);
+ aio_free_ring(ctx);
+ mmdrop(ctx->mm);
+ ctx->mm = NULL;
+ pr_debug("__put_ioctx: freeing %p\n", ctx);
+ kmem_cache_free(kioctx_cachep, ctx);
+
+ if (nr_events) {
+ spin_lock(&aio_nr_lock);
+ BUG_ON(aio_nr - nr_events > aio_nr);
+ aio_nr -= nr_events;
+ spin_unlock(&aio_nr_lock);
+ }
+}
+
+#define get_ioctx(kioctx) do { \
+ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
+ atomic_inc(&(kioctx)->users); \
+} while (0)
+#define put_ioctx(kioctx) do { \
+ BUG_ON(atomic_read(&(kioctx)->users) <= 0); \
+ if (unlikely(atomic_dec_and_test(&(kioctx)->users))) \
+ __put_ioctx(kioctx); \
+} while (0)
+
/* ioctx_alloc
* Allocates and initializes an ioctx. Returns an ERR_PTR if it failed.
*/
@@ -240,7 +277,7 @@ static struct kioctx *ioctx_alloc(unsigned nr_events)
if (ctx->max_reqs == 0)
goto out_cleanup;
- /* now link into global list. kludge. FIXME */
+ /* now link into global list. */
write_lock(&mm->ioctx_list_lock);
ctx->next = mm->ioctx_list;
mm->ioctx_list = ctx;
@@ -361,32 +398,6 @@ void exit_aio(struct mm_struct *mm)
}
}
-/* __put_ioctx
- * Called when the last user of an aio context has gone away,
- * and the struct needs to be freed.
- */
-void __put_ioctx(struct kioctx *ctx)
-{
- unsigned nr_events = ctx->max_reqs;
-
- BUG_ON(ctx->reqs_active);
-
- cancel_delayed_work(&ctx->wq);
- cancel_work_sync(&ctx->wq.work);
- aio_free_ring(ctx);
- mmdrop(ctx->mm);
- ctx->mm = NULL;
- pr_debug("__put_ioctx: freeing %p\n", ctx);
- kmem_cache_free(kioctx_cachep, ctx);
-
- if (nr_events) {
- spin_lock(&aio_nr_lock);
- BUG_ON(aio_nr - nr_events > aio_nr);
- aio_nr -= nr_events;
- spin_unlock(&aio_nr_lock);
- }
-}
-
/* aio_get_req
* Allocate a slot for an aio request. Increments the users count
* of the kioctx so that the kioctx stays around until all requests are
@@ -542,10 +553,7 @@ int aio_put_req(struct kiocb *req)
return ret;
}
-/* Lookup an ioctx id. ioctx_list is lockless for reads.
- * FIXME: this is O(n) and is only suitable for development.
- */
-struct kioctx *lookup_ioctx(unsigned long ctx_id)
+static struct kioctx *lookup_ioctx(unsigned long ctx_id)
{
struct kioctx *ioctx;
struct mm_struct *mm;
@@ -1552,7 +1560,7 @@ static int aio_wake_function(wait_queue_t *wait, unsigned mode,
return 1;
}
-int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
+static int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
struct iocb *iocb)
{
struct kiocb *req;
@@ -1593,7 +1601,7 @@ int io_submit_one(struct kioctx *ctx, struct iocb __user *user_iocb,
* event using the eventfd_signal() function.
*/
req->ki_eventfd = eventfd_fget((int) iocb->aio_resfd);
- if (unlikely(IS_ERR(req->ki_eventfd))) {
+ if (IS_ERR(req->ki_eventfd)) {
ret = PTR_ERR(req->ki_eventfd);
goto out_put_req;
}
diff --git a/fs/autofs4/root.c b/fs/autofs4/root.c
index a54a946a50ae..aa4c5ff8a40d 100644
--- a/fs/autofs4/root.c
+++ b/fs/autofs4/root.c
@@ -533,9 +533,9 @@ static struct dentry *autofs4_lookup_unhashed(struct autofs_sb_info *sbi, struct
goto next;
if (d_unhashed(dentry)) {
- struct autofs_info *ino = autofs4_dentry_ino(dentry);
struct inode *inode = dentry->d_inode;
+ ino = autofs4_dentry_ino(dentry);
list_del_init(&ino->rehash);
dget(dentry);
/*
diff --git a/fs/befs/linuxvfs.c b/fs/befs/linuxvfs.c
index 82123ff3e1dd..e8717de3bab3 100644
--- a/fs/befs/linuxvfs.c
+++ b/fs/befs/linuxvfs.c
@@ -489,9 +489,9 @@ static void befs_put_link(struct dentry *dentry, struct nameidata *nd, void *p)
{
befs_inode_info *befs_ino = BEFS_I(dentry->d_inode);
if (befs_ino->i_flags & BEFS_LONG_SYMLINK) {
- char *p = nd_get_link(nd);
- if (!IS_ERR(p))
- kfree(p);
+ char *link = nd_get_link(nd);
+ if (!IS_ERR(link))
+ kfree(link);
}
}
diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c
index a1bb2244cac7..ba4cddb92f1d 100644
--- a/fs/binfmt_aout.c
+++ b/fs/binfmt_aout.c
@@ -372,21 +372,17 @@ static int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
flush_icache_range(text_addr, text_addr+ex.a_text+ex.a_data);
} else {
- static unsigned long error_time, error_time2;
if ((ex.a_text & 0xfff || ex.a_data & 0xfff) &&
- (N_MAGIC(ex) != NMAGIC) && (jiffies-error_time2) > 5*HZ)
+ (N_MAGIC(ex) != NMAGIC) && printk_ratelimit())
{
printk(KERN_NOTICE "executable not page aligned\n");
- error_time2 = jiffies;
}
- if ((fd_offset & ~PAGE_MASK) != 0 &&
- (jiffies-error_time) > 5*HZ)
+ if ((fd_offset & ~PAGE_MASK) != 0 && printk_ratelimit())
{
printk(KERN_WARNING
"fd_offset is not page aligned. Please convert program: %s\n",
bprm->file->f_path.dentry->d_name.name);
- error_time = jiffies;
}
if (!bprm->file->f_op->mmap||((fd_offset & ~PAGE_MASK) != 0)) {
@@ -495,15 +491,13 @@ static int load_aout_library(struct file *file)
start_addr = ex.a_entry & 0xfffff000;
if ((N_TXTOFF(ex) & ~PAGE_MASK) != 0) {
- static unsigned long error_time;
loff_t pos = N_TXTOFF(ex);
- if ((jiffies-error_time) > 5*HZ)
+ if (printk_ratelimit())
{
printk(KERN_WARNING
"N_TXTOFF is not page aligned. Please convert library: %s\n",
file->f_path.dentry->d_name.name);
- error_time = jiffies;
}
down_write(&current->mm->mmap_sem);
do_brk(start_addr, ex.a_text + ex.a_data + ex.a_bss);
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 9924581df6f6..b25707fee2cc 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1255,26 +1255,23 @@ static int writenote(struct memelfnote *men, struct file *file,
static void fill_elf_header(struct elfhdr *elf, int segs,
u16 machine, u32 flags, u8 osabi)
{
+ memset(elf, 0, sizeof(*elf));
+
memcpy(elf->e_ident, ELFMAG, SELFMAG);
elf->e_ident[EI_CLASS] = ELF_CLASS;
elf->e_ident[EI_DATA] = ELF_DATA;
elf->e_ident[EI_VERSION] = EV_CURRENT;
elf->e_ident[EI_OSABI] = ELF_OSABI;
- memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
elf->e_type = ET_CORE;
elf->e_machine = machine;
elf->e_version = EV_CURRENT;
- elf->e_entry = 0;
elf->e_phoff = sizeof(struct elfhdr);
- elf->e_shoff = 0;
elf->e_flags = flags;
elf->e_ehsize = sizeof(struct elfhdr);
elf->e_phentsize = sizeof(struct elf_phdr);
elf->e_phnum = segs;
- elf->e_shentsize = 0;
- elf->e_shnum = 0;
- elf->e_shstrndx = 0;
+
return;
}
@@ -1725,26 +1722,25 @@ static int fill_note_info(struct elfhdr *elf, int phdrs,
info->thread_status_size = 0;
if (signr) {
- struct elf_thread_status *tmp;
+ struct elf_thread_status *ets;
rcu_read_lock();
do_each_thread(g, p)
if (current->mm == p->mm && current != p) {
- tmp = kzalloc(sizeof(*tmp), GFP_ATOMIC);
- if (!tmp) {
+ ets = kzalloc(sizeof(*ets), GFP_ATOMIC);
+ if (!ets) {
rcu_read_unlock();
return 0;
}
- tmp->thread = p;
- list_add(&tmp->list, &info->thread_list);
+ ets->thread = p;
+ list_add(&ets->list, &info->thread_list);
}
while_each_thread(g, p);
rcu_read_unlock();
list_for_each(t, &info->thread_list) {
- struct elf_thread_status *tmp;
int sz;
- tmp = list_entry(t, struct elf_thread_status, list);
- sz = elf_dump_thread_status(signr, tmp);
+ ets = list_entry(t, struct elf_thread_status, list);
+ sz = elf_dump_thread_status(signr, ets);
info->thread_status_size += sz;
}
}
@@ -2000,10 +1996,10 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) {
struct page *page;
- struct vm_area_struct *vma;
+ struct vm_area_struct *tmp_vma;
if (get_user_pages(current, current->mm, addr, 1, 0, 1,
- &page, &vma) <= 0) {
+ &page, &tmp_vma) <= 0) {
DUMP_SEEK(PAGE_SIZE);
} else {
if (page == ZERO_PAGE(0)) {
@@ -2013,7 +2009,7 @@ static int elf_core_dump(long signr, struct pt_regs *regs, struct file *file, un
}
} else {
void *kaddr;
- flush_cache_page(vma, addr,
+ flush_cache_page(tmp_vma, addr,
page_to_pfn(page));
kaddr = kmap(page);
if ((size += PAGE_SIZE) > limit ||
diff --git a/fs/binfmt_elf_fdpic.c b/fs/binfmt_elf_fdpic.c
index 32649f2a1654..ddd35d873391 100644
--- a/fs/binfmt_elf_fdpic.c
+++ b/fs/binfmt_elf_fdpic.c
@@ -136,8 +136,8 @@ static int elf_fdpic_fetch_phdrs(struct elf_fdpic_params *params,
retval = kernel_read(file, params->hdr.e_phoff,
(char *) params->phdrs, size);
- if (retval < 0)
- return retval;
+ if (unlikely(retval != size))
+ return retval < 0 ? retval : -ENOEXEC;
/* determine stack size for this binary */
phdr = params->phdrs;
@@ -218,8 +218,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
phdr->p_offset,
interpreter_name,
phdr->p_filesz);
- if (retval < 0)
+ if (unlikely(retval != phdr->p_filesz)) {
+ if (retval >= 0)
+ retval = -ENOEXEC;
goto error;
+ }
retval = -ENOENT;
if (interpreter_name[phdr->p_filesz - 1] != '\0')
@@ -245,8 +248,11 @@ static int load_elf_fdpic_binary(struct linux_binprm *bprm,
retval = kernel_read(interpreter, 0, bprm->buf,
BINPRM_BUF_SIZE);
- if (retval < 0)
+ if (unlikely(retval != BINPRM_BUF_SIZE)) {
+ if (retval >= 0)
+ retval = -ENOEXEC;
goto error;
+ }
interp_params.hdr = *((struct elfhdr *) bprm->buf);
break;
diff --git a/fs/binfmt_em86.c b/fs/binfmt_em86.c
index f95ae9789c91..f9c88d0c8ced 100644
--- a/fs/binfmt_em86.c
+++ b/fs/binfmt_em86.c
@@ -43,7 +43,7 @@ static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs)
return -ENOEXEC;
}
- bprm->sh_bang++; /* Well, the bang-shell is implicit... */
+ bprm->sh_bang = 1; /* Well, the bang-shell is implicit... */
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/binfmt_flat.c b/fs/binfmt_flat.c
index 0498b181dd52..3b40d45a3a16 100644
--- a/fs/binfmt_flat.c
+++ b/fs/binfmt_flat.c
@@ -531,7 +531,8 @@ static int load_flat_file(struct linux_binprm * bprm,
DBG_FLT("BINFMT_FLAT: ROM mapping of file (we hope)\n");
down_write(&current->mm->mmap_sem);
- textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC, MAP_PRIVATE, 0);
+ textpos = do_mmap(bprm->file, 0, text_len, PROT_READ|PROT_EXEC,
+ MAP_PRIVATE|MAP_EXECUTABLE, 0);
up_write(&current->mm->mmap_sem);
if (!textpos || textpos >= (unsigned long) -4096) {
if (!textpos)
@@ -932,14 +933,8 @@ static int __init init_flat_binfmt(void)
return register_binfmt(&flat_format);
}
-static void __exit exit_flat_binfmt(void)
-{
- unregister_binfmt(&flat_format);
-}
-
/****************************************************************************/
core_initcall(init_flat_binfmt);
-module_exit(exit_flat_binfmt);
/****************************************************************************/
diff --git a/fs/binfmt_misc.c b/fs/binfmt_misc.c
index dbf0ac0523de..7191306367c5 100644
--- a/fs/binfmt_misc.c
+++ b/fs/binfmt_misc.c
@@ -115,6 +115,12 @@ static int load_misc_binary(struct linux_binprm *bprm, struct pt_regs *regs)
if (!enabled)
goto _ret;
+ retval = -ENOEXEC;
+ if (bprm->misc_bang)
+ goto _ret;
+
+ bprm->misc_bang = 1;
+
/* to keep locking time low, we copy the interpreter string */
read_lock(&entries_lock);
fmt = check_file(bprm);
diff --git a/fs/binfmt_script.c b/fs/binfmt_script.c
index ab33939b12a7..9e3963f7ebf1 100644
--- a/fs/binfmt_script.c
+++ b/fs/binfmt_script.c
@@ -29,7 +29,7 @@ static int load_script(struct linux_binprm *bprm,struct pt_regs *regs)
* Sorta complicated, but hopefully it will work. -TYT
*/
- bprm->sh_bang++;
+ bprm->sh_bang = 1;
allow_write_access(bprm->file);
fput(bprm->file);
bprm->file = NULL;
diff --git a/fs/buffer.c b/fs/buffer.c
index 3db4a26adc44..189efa4efc6e 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -2211,8 +2211,8 @@ out:
return err;
}
-int cont_expand_zero(struct file *file, struct address_space *mapping,
- loff_t pos, loff_t *bytes)
+static int cont_expand_zero(struct file *file, struct address_space *mapping,
+ loff_t pos, loff_t *bytes)
{
struct inode *inode = mapping->host;
unsigned blocksize = 1 << inode->i_blkbits;
@@ -2328,23 +2328,6 @@ int block_commit_write(struct page *page, unsigned from, unsigned to)
return 0;
}
-int generic_commit_write(struct file *file, struct page *page,
- unsigned from, unsigned to)
-{
- struct inode *inode = page->mapping->host;
- loff_t pos = ((loff_t)page->index << PAGE_CACHE_SHIFT) + to;
- __block_commit_write(inode,page,from,to);
- /*
- * No need to use i_size_read() here, the i_size
- * cannot change under us because we hold i_mutex.
- */
- if (pos > inode->i_size) {
- i_size_write(inode, pos);
- mark_inode_dirty(inode);
- }
- return 0;
-}
-
/*
* block_page_mkwrite() is not allowed to change the file size as it gets
* called from a page fault handler when a page is first dirtied. Hence we must
@@ -3315,7 +3298,6 @@ EXPORT_SYMBOL(end_buffer_write_sync);
EXPORT_SYMBOL(file_fsync);
EXPORT_SYMBOL(fsync_bdev);
EXPORT_SYMBOL(generic_block_bmap);
-EXPORT_SYMBOL(generic_commit_write);
EXPORT_SYMBOL(generic_cont_expand_simple);
EXPORT_SYMBOL(init_buffer);
EXPORT_SYMBOL(invalidate_bdev);
diff --git a/fs/char_dev.c b/fs/char_dev.c
index 038674aa88a7..68e510b88457 100644
--- a/fs/char_dev.c
+++ b/fs/char_dev.c
@@ -55,7 +55,6 @@ static struct char_device_struct {
unsigned int baseminor;
int minorct;
char name[64];
- struct file_operations *fops;
struct cdev *cdev; /* will die */
} *chrdevs[CHRDEV_MAJOR_HASH_SIZE];
diff --git a/fs/cifs/cifs_debug.c b/fs/cifs/cifs_debug.c
index 0228ed06069e..cc950f69e51e 100644
--- a/fs/cifs/cifs_debug.c
+++ b/fs/cifs/cifs_debug.c
@@ -468,7 +468,7 @@ cifs_proc_init(void)
{
struct proc_dir_entry *pde;
- proc_fs_cifs = proc_mkdir("cifs", proc_root_fs);
+ proc_fs_cifs = proc_mkdir("fs/cifs", NULL);
if (proc_fs_cifs == NULL)
return;
@@ -559,7 +559,7 @@ cifs_proc_clean(void)
remove_proc_entry("LinuxExtensionsEnabled", proc_fs_cifs);
remove_proc_entry("Experimental", proc_fs_cifs);
remove_proc_entry("LookupCacheEnabled", proc_fs_cifs);
- remove_proc_entry("cifs", proc_root_fs);
+ remove_proc_entry("fs/cifs", NULL);
}
static int
diff --git a/fs/coda/coda_linux.c b/fs/coda/coda_linux.c
index 95a54253c047..e1c854890f94 100644
--- a/fs/coda/coda_linux.c
+++ b/fs/coda/coda_linux.c
@@ -134,7 +134,7 @@ void coda_iattr_to_vattr(struct iattr *iattr, struct coda_vattr *vattr)
unsigned int valid;
/* clean out */
- vattr->va_mode = (umode_t) -1;
+ vattr->va_mode = -1;
vattr->va_uid = (vuid_t) -1;
vattr->va_gid = (vgid_t) -1;
vattr->va_size = (off_t) -1;
diff --git a/fs/coda/dir.c b/fs/coda/dir.c
index f89ff083079b..3d2580e00a3e 100644
--- a/fs/coda/dir.c
+++ b/fs/coda/dir.c
@@ -345,7 +345,7 @@ static int coda_symlink(struct inode *dir_inode, struct dentry *de,
}
/* destruction routines: unlink, rmdir */
-int coda_unlink(struct inode *dir, struct dentry *de)
+static int coda_unlink(struct inode *dir, struct dentry *de)
{
int error;
const char *name = de->d_name.name;
@@ -365,7 +365,7 @@ int coda_unlink(struct inode *dir, struct dentry *de)
return 0;
}
-int coda_rmdir(struct inode *dir, struct dentry *de)
+static int coda_rmdir(struct inode *dir, struct dentry *de)
{
const char *name = de->d_name.name;
int len = de->d_name.len;
@@ -424,7 +424,7 @@ static int coda_rename(struct inode *old_dir, struct dentry *old_dentry,
/* file operations for directories */
-int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
+static int coda_readdir(struct file *coda_file, void *buf, filldir_t filldir)
{
struct coda_file_info *cfi;
struct file *host_file;
diff --git a/fs/drop_caches.c b/fs/drop_caches.c
index 59375efcf39d..3e5637fc3779 100644
--- a/fs/drop_caches.c
+++ b/fs/drop_caches.c
@@ -14,18 +14,26 @@ int sysctl_drop_caches;
static void drop_pagecache_sb(struct super_block *sb)
{
- struct inode *inode;
+ struct inode *inode, *toput_inode = NULL;
spin_lock(&inode_lock);
list_for_each_entry(inode, &sb->s_inodes, i_sb_list) {
if (inode->i_state & (I_FREEING|I_WILL_FREE))
continue;
+ if (inode->i_mapping->nrpages == 0)
+ continue;
+ __iget(inode);
+ spin_unlock(&inode_lock);
__invalidate_mapping_pages(inode->i_mapping, 0, -1, true);
+ iput(toput_inode);
+ toput_inode = inode;
+ spin_lock(&inode_lock);
}
spin_unlock(&inode_lock);
+ iput(toput_inode);
}
-void drop_pagecache(void)
+static void drop_pagecache(void)
{
struct super_block *sb;
@@ -45,7 +53,7 @@ restart:
spin_unlock(&sb_lock);
}
-void drop_slab(void)
+static void drop_slab(void)
{
int nr_objects;
diff --git a/fs/ecryptfs/Makefile b/fs/ecryptfs/Makefile
index 768857015516..1e34a7fd4884 100644
--- a/fs/ecryptfs/Makefile
+++ b/fs/ecryptfs/Makefile
@@ -4,4 +4,4 @@
obj-$(CONFIG_ECRYPT_FS) += ecryptfs.o
-ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o debug.o
+ecryptfs-objs := dentry.o file.o inode.o main.o super.o mmap.o read_write.o crypto.o keystore.o messaging.o netlink.o miscdev.o debug.o
diff --git a/fs/ecryptfs/crypto.c b/fs/ecryptfs/crypto.c
index a066e109ad9c..cd62d75b2cc0 100644
--- a/fs/ecryptfs/crypto.c
+++ b/fs/ecryptfs/crypto.c
@@ -119,21 +119,21 @@ static int ecryptfs_calculate_md5(char *dst,
if (rc) {
printk(KERN_ERR
"%s: Error initializing crypto hash; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
rc = crypto_hash_update(&desc, &sg, len);
if (rc) {
printk(KERN_ERR
"%s: Error updating crypto hash; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
rc = crypto_hash_final(&desc, dst);
if (rc) {
printk(KERN_ERR
"%s: Error finalizing crypto hash; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
out:
@@ -437,7 +437,7 @@ static int ecryptfs_encrypt_extent(struct page *enc_extent_page,
if (rc < 0) {
printk(KERN_ERR "%s: Error attempting to encrypt page with "
"page->index = [%ld], extent_offset = [%ld]; "
- "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
+ "rc = [%d]\n", __func__, page->index, extent_offset,
rc);
goto out;
}
@@ -487,7 +487,7 @@ int ecryptfs_encrypt_page(struct page *page)
0, PAGE_CACHE_SIZE);
if (rc)
printk(KERN_ERR "%s: Error attempting to copy "
- "page at index [%ld]\n", __FUNCTION__,
+ "page at index [%ld]\n", __func__,
page->index);
goto out;
}
@@ -508,7 +508,7 @@ int ecryptfs_encrypt_page(struct page *page)
extent_offset);
if (rc) {
printk(KERN_ERR "%s: Error encrypting extent; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out;
}
ecryptfs_lower_offset_for_extent(
@@ -569,7 +569,7 @@ static int ecryptfs_decrypt_extent(struct page *page,
if (rc < 0) {
printk(KERN_ERR "%s: Error attempting to decrypt to page with "
"page->index = [%ld], extent_offset = [%ld]; "
- "rc = [%d]\n", __FUNCTION__, page->index, extent_offset,
+ "rc = [%d]\n", __func__, page->index, extent_offset,
rc);
goto out;
}
@@ -622,7 +622,7 @@ int ecryptfs_decrypt_page(struct page *page)
ecryptfs_inode);
if (rc)
printk(KERN_ERR "%s: Error attempting to copy "
- "page at index [%ld]\n", __FUNCTION__,
+ "page at index [%ld]\n", __func__,
page->index);
goto out;
}
@@ -656,7 +656,7 @@ int ecryptfs_decrypt_page(struct page *page)
extent_offset);
if (rc) {
printk(KERN_ERR "%s: Error encrypting extent; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out;
}
}
@@ -1215,7 +1215,7 @@ int ecryptfs_read_and_validate_header_region(char *data,
ecryptfs_inode);
if (rc) {
printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out;
}
if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) {
@@ -1246,7 +1246,6 @@ ecryptfs_write_header_metadata(char *virt,
(*written) = 6;
}
-struct kmem_cache *ecryptfs_header_cache_0;
struct kmem_cache *ecryptfs_header_cache_1;
struct kmem_cache *ecryptfs_header_cache_2;
@@ -1320,7 +1319,7 @@ ecryptfs_write_metadata_to_contents(struct ecryptfs_crypt_stat *crypt_stat,
0, crypt_stat->num_header_bytes_at_front);
if (rc)
printk(KERN_ERR "%s: Error attempting to write header "
- "information to lower file; rc = [%d]\n", __FUNCTION__,
+ "information to lower file; rc = [%d]\n", __func__,
rc);
return rc;
}
@@ -1365,14 +1364,14 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
}
} else {
printk(KERN_WARNING "%s: Encrypted flag not set\n",
- __FUNCTION__);
+ __func__);
rc = -EINVAL;
goto out;
}
/* Released in this function */
virt = kzalloc(crypt_stat->num_header_bytes_at_front, GFP_KERNEL);
if (!virt) {
- printk(KERN_ERR "%s: Out of memory\n", __FUNCTION__);
+ printk(KERN_ERR "%s: Out of memory\n", __func__);
rc = -ENOMEM;
goto out;
}
@@ -1380,7 +1379,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
ecryptfs_dentry);
if (unlikely(rc)) {
printk(KERN_ERR "%s: Error whilst writing headers; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
goto out_free;
}
if (crypt_stat->flags & ECRYPTFS_METADATA_IN_XATTR)
@@ -1391,7 +1390,7 @@ int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)
ecryptfs_dentry, virt);
if (rc) {
printk(KERN_ERR "%s: Error writing metadata out to lower file; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out_free;
}
out_free:
@@ -1585,7 +1584,7 @@ int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry)
if (!page_virt) {
rc = -ENOMEM;
printk(KERN_ERR "%s: Unable to allocate page_virt\n",
- __FUNCTION__);
+ __func__);
goto out;
}
rc = ecryptfs_read_lower(page_virt, 0, crypt_stat->extent_size,
diff --git a/fs/ecryptfs/ecryptfs_kernel.h b/fs/ecryptfs/ecryptfs_kernel.h
index 5007f788da01..951ee33a022d 100644
--- a/fs/ecryptfs/ecryptfs_kernel.h
+++ b/fs/ecryptfs/ecryptfs_kernel.h
@@ -4,7 +4,7 @@
*
* Copyright (C) 1997-2003 Erez Zadok
* Copyright (C) 2001-2003 Stony Brook University
- * Copyright (C) 2004-2007 International Business Machines Corp.
+ * Copyright (C) 2004-2008 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mahalcro@us.ibm.com>
* Trevor S. Highland <trevor.highland@gmail.com>
* Tyler Hicks <tyhicks@ou.edu>
@@ -34,6 +34,7 @@
#include <linux/namei.h>
#include <linux/scatterlist.h>
#include <linux/hash.h>
+#include <linux/nsproxy.h>
/* Version verification for shared data structures w/ userspace */
#define ECRYPTFS_VERSION_MAJOR 0x00
@@ -49,11 +50,13 @@
#define ECRYPTFS_VERSIONING_POLICY 0x00000008
#define ECRYPTFS_VERSIONING_XATTR 0x00000010
#define ECRYPTFS_VERSIONING_MULTKEY 0x00000020
+#define ECRYPTFS_VERSIONING_DEVMISC 0x00000040
#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \
| ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \
| ECRYPTFS_VERSIONING_PUBKEY \
| ECRYPTFS_VERSIONING_XATTR \
- | ECRYPTFS_VERSIONING_MULTKEY)
+ | ECRYPTFS_VERSIONING_MULTKEY \
+ | ECRYPTFS_VERSIONING_DEVMISC)
#define ECRYPTFS_MAX_PASSWORD_LENGTH 64
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH
#define ECRYPTFS_SALT_SIZE 8
@@ -73,17 +76,14 @@
#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32
#define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ
#define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3)
-#define ECRYPTFS_NLMSG_HELO 100
-#define ECRYPTFS_NLMSG_QUIT 101
-#define ECRYPTFS_NLMSG_REQUEST 102
-#define ECRYPTFS_NLMSG_RESPONSE 103
#define ECRYPTFS_MAX_PKI_NAME_BYTES 16
#define ECRYPTFS_DEFAULT_NUM_USERS 4
#define ECRYPTFS_MAX_NUM_USERS 32768
#define ECRYPTFS_TRANSPORT_NETLINK 0
#define ECRYPTFS_TRANSPORT_CONNECTOR 1
#define ECRYPTFS_TRANSPORT_RELAYFS 2
-#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_NETLINK
+#define ECRYPTFS_TRANSPORT_MISCDEV 3
+#define ECRYPTFS_DEFAULT_TRANSPORT ECRYPTFS_TRANSPORT_MISCDEV
#define ECRYPTFS_XATTR_NAME "user.ecryptfs"
#define RFC2440_CIPHER_DES3_EDE 0x02
@@ -366,32 +366,63 @@ struct ecryptfs_auth_tok_list_item {
};
struct ecryptfs_message {
+ /* Can never be greater than ecryptfs_message_buf_len */
+ /* Used to find the parent msg_ctx */
+ /* Inherits from msg_ctx->index */
u32 index;
u32 data_len;
u8 data[];
};
struct ecryptfs_msg_ctx {
-#define ECRYPTFS_MSG_CTX_STATE_FREE 0x0001
-#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x0002
-#define ECRYPTFS_MSG_CTX_STATE_DONE 0x0003
- u32 state;
- unsigned int index;
- unsigned int counter;
+#define ECRYPTFS_MSG_CTX_STATE_FREE 0x01
+#define ECRYPTFS_MSG_CTX_STATE_PENDING 0x02
+#define ECRYPTFS_MSG_CTX_STATE_DONE 0x03
+#define ECRYPTFS_MSG_CTX_STATE_NO_REPLY 0x04
+ u8 state;
+#define ECRYPTFS_MSG_HELO 100
+#define ECRYPTFS_MSG_QUIT 101
+#define ECRYPTFS_MSG_REQUEST 102
+#define ECRYPTFS_MSG_RESPONSE 103
+ u8 type;
+ u32 index;
+ /* Counter converts to a sequence number. Each message sent
+ * out for which we expect a response has an associated
+ * sequence number. The response must have the same sequence
+ * number as the counter for the msg_stc for the message to be
+ * valid. */
+ u32 counter;
+ size_t msg_size;
struct ecryptfs_message *msg;
struct task_struct *task;
struct list_head node;
+ struct list_head daemon_out_list;
struct mutex mux;
};
extern unsigned int ecryptfs_transport;
-struct ecryptfs_daemon_id {
- pid_t pid;
- uid_t uid;
- struct hlist_node id_chain;
+struct ecryptfs_daemon;
+
+struct ecryptfs_daemon {
+#define ECRYPTFS_DAEMON_IN_READ 0x00000001
+#define ECRYPTFS_DAEMON_IN_POLL 0x00000002
+#define ECRYPTFS_DAEMON_ZOMBIE 0x00000004
+#define ECRYPTFS_DAEMON_MISCDEV_OPEN 0x00000008
+ u32 flags;
+ u32 num_queued_msg_ctx;
+ struct pid *pid;
+ uid_t euid;
+ struct user_namespace *user_ns;
+ struct task_struct *task;
+ struct mutex mux;
+ struct list_head msg_ctx_out_queue;
+ wait_queue_head_t wait;
+ struct hlist_node euid_chain;
};
+extern struct mutex ecryptfs_daemon_hash_mux;
+
static inline struct ecryptfs_file_info *
ecryptfs_file_to_private(struct file *file)
{
@@ -500,7 +531,7 @@ ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)
}
#define ecryptfs_printk(type, fmt, arg...) \
- __ecryptfs_printk(type "%s: " fmt, __FUNCTION__, ## arg);
+ __ecryptfs_printk(type "%s: " fmt, __func__, ## arg);
void __ecryptfs_printk(const char *fmt, ...);
extern const struct file_operations ecryptfs_main_fops;
@@ -581,10 +612,13 @@ int
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags);
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);
-int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid);
-int ecryptfs_process_quit(uid_t uid, pid_t pid);
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
- pid_t pid, u32 seq);
+int ecryptfs_process_helo(unsigned int transport, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid);
+int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid);
+int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid,
+ u32 seq);
int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
struct ecryptfs_msg_ctx **msg_ctx);
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
@@ -593,14 +627,14 @@ int ecryptfs_init_messaging(unsigned int transport);
void ecryptfs_release_messaging(unsigned int transport);
int ecryptfs_send_netlink(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
- u16 msg_flags, pid_t daemon_pid);
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct pid *daemon_pid);
int ecryptfs_init_netlink(void);
void ecryptfs_release_netlink(void);
int ecryptfs_send_connector(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
- u16 msg_flags, pid_t daemon_pid);
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct pid *daemon_pid);
int ecryptfs_init_connector(void);
void ecryptfs_release_connector(void);
void
@@ -642,5 +676,21 @@ int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,
size_t offset_in_page, size_t size,
struct inode *ecryptfs_inode);
struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);
+int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns);
+int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
+ size_t *length_size);
+int ecryptfs_write_packet_length(char *dest, size_t size,
+ size_t *packet_size_length);
+int ecryptfs_init_ecryptfs_miscdev(void);
+void ecryptfs_destroy_ecryptfs_miscdev(void);
+int ecryptfs_send_miscdev(char *data, size_t data_size,
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct ecryptfs_daemon *daemon);
+void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);
+int
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid);
#endif /* #ifndef ECRYPTFS_KERNEL_H */
diff --git a/fs/ecryptfs/file.c b/fs/ecryptfs/file.c
index 2b8f5ed4adea..2258b8f654a6 100644
--- a/fs/ecryptfs/file.c
+++ b/fs/ecryptfs/file.c
@@ -195,7 +195,9 @@ static int ecryptfs_open(struct inode *inode, struct file *file)
file, ecryptfs_inode_to_private(inode)->lower_file);
if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {
ecryptfs_printk(KERN_DEBUG, "This is a directory\n");
+ mutex_lock(&crypt_stat->cs_mutex);
crypt_stat->flags &= ~(ECRYPTFS_ENCRYPTED);
+ mutex_unlock(&crypt_stat->cs_mutex);
rc = 0;
goto out;
}
diff --git a/fs/ecryptfs/inode.c b/fs/ecryptfs/inode.c
index e23861152101..0a1397335a8e 100644
--- a/fs/ecryptfs/inode.c
+++ b/fs/ecryptfs/inode.c
@@ -111,7 +111,7 @@ ecryptfs_do_create(struct inode *directory_inode,
lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);
lower_dir_dentry = lock_parent(lower_dentry);
- if (unlikely(IS_ERR(lower_dir_dentry))) {
+ if (IS_ERR(lower_dir_dentry)) {
ecryptfs_printk(KERN_ERR, "Error locking directory of "
"dentry\n");
rc = PTR_ERR(lower_dir_dentry);
@@ -121,7 +121,7 @@ ecryptfs_do_create(struct inode *directory_inode,
ecryptfs_dentry, mode, nd);
if (rc) {
printk(KERN_ERR "%s: Failure to create dentry in lower fs; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
goto out_lock;
}
rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,
@@ -908,7 +908,9 @@ static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)
if (ia->ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
ia->ia_valid &= ~ATTR_MODE;
+ mutex_lock(&lower_dentry->d_inode->i_mutex);
rc = notify_change(lower_dentry, ia);
+ mutex_unlock(&lower_dentry->d_inode->i_mutex);
out:
fsstack_copy_attr_all(inode, lower_inode, NULL);
return rc;
diff --git a/fs/ecryptfs/keystore.c b/fs/ecryptfs/keystore.c
index 682b1b2482c2..e82b457180be 100644
--- a/fs/ecryptfs/keystore.c
+++ b/fs/ecryptfs/keystore.c
@@ -65,7 +65,7 @@ static int process_request_key_err(long err_code)
}
/**
- * parse_packet_length
+ * ecryptfs_parse_packet_length
* @data: Pointer to memory containing length at offset
* @size: This function writes the decoded size to this memory
* address; zero on error
@@ -73,8 +73,8 @@ static int process_request_key_err(long err_code)
*
* Returns zero on success; non-zero on error
*/
-static int parse_packet_length(unsigned char *data, size_t *size,
- size_t *length_size)
+int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,
+ size_t *length_size)
{
int rc = 0;
@@ -105,7 +105,7 @@ out:
}
/**
- * write_packet_length
+ * ecryptfs_write_packet_length
* @dest: The byte array target into which to write the length. Must
* have at least 5 bytes allocated.
* @size: The length to write.
@@ -114,8 +114,8 @@ out:
*
* Returns zero on success; non-zero on error.
*/
-static int write_packet_length(char *dest, size_t size,
- size_t *packet_size_length)
+int ecryptfs_write_packet_length(char *dest, size_t size,
+ size_t *packet_size_length)
{
int rc = 0;
@@ -162,8 +162,8 @@ write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,
goto out;
}
message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE;
- rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
"header; cannot generate packet length\n");
@@ -172,8 +172,9 @@ write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,
i += packet_size_len;
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX;
- rc = write_packet_length(&message[i], session_key->encrypted_key_size,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i],
+ session_key->encrypted_key_size,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 64 packet "
"header; cannot generate packet length\n");
@@ -225,7 +226,7 @@ parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,
rc = -EIO;
goto out;
}
- rc = parse_packet_length(&data[i], &m_size, &data_len);
+ rc = ecryptfs_parse_packet_length(&data[i], &m_size, &data_len);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc);
@@ -304,8 +305,8 @@ write_tag_66_packet(char *signature, u8 cipher_code,
goto out;
}
message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE;
- rc = write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i], ECRYPTFS_SIG_SIZE_HEX,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
"header; cannot generate packet length\n");
@@ -315,8 +316,8 @@ write_tag_66_packet(char *signature, u8 cipher_code,
memcpy(&message[i], signature, ECRYPTFS_SIG_SIZE_HEX);
i += ECRYPTFS_SIG_SIZE_HEX;
/* The encrypted key includes 1 byte cipher code and 2 byte checksum */
- rc = write_packet_length(&message[i], crypt_stat->key_size + 3,
- &packet_size_len);
+ rc = ecryptfs_write_packet_length(&message[i], crypt_stat->key_size + 3,
+ &packet_size_len);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 66 packet "
"header; cannot generate packet length\n");
@@ -357,20 +358,25 @@ parse_tag_67_packet(struct ecryptfs_key_record *key_rec,
/* verify that everything through the encrypted FEK size is present */
if (message_len < 4) {
rc = -EIO;
+ printk(KERN_ERR "%s: message_len is [%Zd]; minimum acceptable "
+ "message length is [%d]\n", __func__, message_len, 4);
goto out;
}
if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {
- ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_67\n");
rc = -EIO;
+ printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n",
+ __func__);
goto out;
}
if (data[i++]) {
- ecryptfs_printk(KERN_ERR, "Status indicator has non zero value"
- " [%d]\n", data[i-1]);
rc = -EIO;
+ printk(KERN_ERR "%s: Status indicator has non zero "
+ "value [%d]\n", __func__, data[i-1]);
+
goto out;
}
- rc = parse_packet_length(&data[i], &key_rec->enc_key_size, &data_len);
+ rc = ecryptfs_parse_packet_length(&data[i], &key_rec->enc_key_size,
+ &data_len);
if (rc) {
ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "
"rc = [%d]\n", rc);
@@ -378,17 +384,17 @@ parse_tag_67_packet(struct ecryptfs_key_record *key_rec,
}
i += data_len;
if (message_len < (i + key_rec->enc_key_size)) {
- ecryptfs_printk(KERN_ERR, "message_len [%d]; max len is [%d]\n",
- message_len, (i + key_rec->enc_key_size));
rc = -EIO;
+ printk(KERN_ERR "%s: message_len [%Zd]; max len is [%Zd]\n",
+ __func__, message_len, (i + key_rec->enc_key_size));
goto out;
}
if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {
- ecryptfs_printk(KERN_ERR, "Encrypted key_size [%d] larger than "
- "the maximum key size [%d]\n",
- key_rec->enc_key_size,
- ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
rc = -EIO;
+ printk(KERN_ERR "%s: Encrypted key_size [%Zd] larger than "
+ "the maximum key size [%d]\n", __func__,
+ key_rec->enc_key_size,
+ ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);
goto out;
}
memcpy(key_rec->enc_key, &data[i], key_rec->enc_key_size);
@@ -445,7 +451,7 @@ decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,
rc = write_tag_64_packet(auth_tok_sig, &(auth_tok->session_key),
&netlink_message, &netlink_message_length);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet");
+ ecryptfs_printk(KERN_ERR, "Failed to write tag 64 packet\n");
goto out;
}
rc = ecryptfs_send_message(ecryptfs_transport, netlink_message,
@@ -570,8 +576,8 @@ parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat,
goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
- rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size);
+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
if (rc) {
printk(KERN_WARNING "Error parsing packet length; "
"rc = [%d]\n", rc);
@@ -704,8 +710,8 @@ parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,
goto out;
}
(*new_auth_tok) = &auth_tok_list_item->auth_tok;
- rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size);
+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
if (rc) {
printk(KERN_WARNING "Error parsing packet length; rc = [%d]\n",
rc);
@@ -852,8 +858,8 @@ parse_tag_11_packet(unsigned char *data, unsigned char *contents,
rc = -EINVAL;
goto out;
}
- rc = parse_packet_length(&data[(*packet_size)], &body_size,
- &length_size);
+ rc = ecryptfs_parse_packet_length(&data[(*packet_size)], &body_size,
+ &length_size);
if (rc) {
printk(KERN_WARNING "Invalid tag 11 packet format\n");
goto out;
@@ -1405,8 +1411,8 @@ write_tag_1_packet(char *dest, size_t *remaining_bytes,
auth_tok->token.private_key.key_size;
rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);
if (rc) {
- ecryptfs_printk(KERN_ERR, "Failed to encrypt session key "
- "via a pki");
+ printk(KERN_ERR "Failed to encrypt session key via a key "
+ "module; rc = [%d]\n", rc);
goto out;
}
if (ecryptfs_verbosity > 0) {
@@ -1430,8 +1436,9 @@ encrypted_session_key_set:
goto out;
}
dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE;
- rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4),
- &packet_size_length);
+ rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
+ (max_packet_size - 4),
+ &packet_size_length);
if (rc) {
ecryptfs_printk(KERN_ERR, "Error generating tag 1 packet "
"header; cannot generate packet length\n");
@@ -1489,8 +1496,9 @@ write_tag_11_packet(char *dest, size_t *remaining_bytes, char *contents,
goto out;
}
dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;
- rc = write_packet_length(&dest[(*packet_length)],
- (max_packet_size - 4), &packet_size_length);
+ rc = ecryptfs_write_packet_length(&dest[(*packet_length)],
+ (max_packet_size - 4),
+ &packet_size_length);
if (rc) {
printk(KERN_ERR "Error generating tag 11 packet header; cannot "
"generate packet length. rc = [%d]\n", rc);
@@ -1682,8 +1690,9 @@ encrypted_session_key_set:
dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;
/* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3)
* to get the number of octets in the actual Tag 3 packet */
- rc = write_packet_length(&dest[(*packet_size)], (max_packet_size - 4),
- &packet_size_length);
+ rc = ecryptfs_write_packet_length(&dest[(*packet_size)],
+ (max_packet_size - 4),
+ &packet_size_length);
if (rc) {
printk(KERN_ERR "Error generating tag 3 packet header; cannot "
"generate packet length. rc = [%d]\n", rc);
diff --git a/fs/ecryptfs/main.c b/fs/ecryptfs/main.c
index d25ac9500a92..d603631601eb 100644
--- a/fs/ecryptfs/main.c
+++ b/fs/ecryptfs/main.c
@@ -219,7 +219,7 @@ int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,
if (rc) {
printk(KERN_ERR "%s: Error attempting to initialize the "
"persistent file for the dentry with name [%s]; "
- "rc = [%d]\n", __FUNCTION__, dentry->d_name.name, rc);
+ "rc = [%d]\n", __func__, dentry->d_name.name, rc);
goto out;
}
out:
diff --git a/fs/ecryptfs/messaging.c b/fs/ecryptfs/messaging.c
index 9cc2aec27b0d..1b5c20058acb 100644
--- a/fs/ecryptfs/messaging.c
+++ b/fs/ecryptfs/messaging.c
@@ -1,7 +1,7 @@
/**
* eCryptfs: Linux filesystem encryption layer
*
- * Copyright (C) 2004-2006 International Business Machines Corp.
+ * Copyright (C) 2004-2008 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Tyler Hicks <tyhicks@ou.edu>
*
@@ -20,19 +20,21 @@
* 02111-1307, USA.
*/
#include <linux/sched.h>
+#include <linux/user_namespace.h>
+#include <linux/nsproxy.h>
#include "ecryptfs_kernel.h"
static LIST_HEAD(ecryptfs_msg_ctx_free_list);
static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);
static struct mutex ecryptfs_msg_ctx_lists_mux;
-static struct hlist_head *ecryptfs_daemon_id_hash;
-static struct mutex ecryptfs_daemon_id_hash_mux;
+static struct hlist_head *ecryptfs_daemon_hash;
+struct mutex ecryptfs_daemon_hash_mux;
static int ecryptfs_hash_buckets;
#define ecryptfs_uid_hash(uid) \
hash_long((unsigned long)uid, ecryptfs_hash_buckets)
-static unsigned int ecryptfs_msg_counter;
+static u32 ecryptfs_msg_counter;
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
/**
@@ -40,9 +42,10 @@ static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;
* @msg_ctx: The context that was acquired from the free list
*
* Acquires a context element from the free list and locks the mutex
- * on the context. Returns zero on success; non-zero on error or upon
- * failure to acquire a free context element. Be sure to lock the
- * list mutex before calling.
+ * on the context. Sets the msg_ctx task to current. Returns zero on
+ * success; non-zero on error or upon failure to acquire a free
+ * context element. Must be called with ecryptfs_msg_ctx_lists_mux
+ * held.
*/
static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
{
@@ -50,11 +53,11 @@ static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)
int rc;
if (list_empty(&ecryptfs_msg_ctx_free_list)) {
- ecryptfs_printk(KERN_WARNING, "The eCryptfs free "
- "context list is empty. It may be helpful to "
- "specify the ecryptfs_message_buf_len "
- "parameter to be greater than the current "
- "value of [%d]\n", ecryptfs_message_buf_len);
+ printk(KERN_WARNING "%s: The eCryptfs free "
+ "context list is empty. It may be helpful to "
+ "specify the ecryptfs_message_buf_len "
+ "parameter to be greater than the current "
+ "value of [%d]\n", __func__, ecryptfs_message_buf_len);
rc = -ENOMEM;
goto out;
}
@@ -75,8 +78,7 @@ out:
* ecryptfs_msg_ctx_free_to_alloc
* @msg_ctx: The context to move from the free list to the alloc list
*
- * Be sure to lock the list mutex and the context mutex before
- * calling.
+ * Must be called with ecryptfs_msg_ctx_lists_mux held.
*/
static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
{
@@ -89,36 +91,39 @@ static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)
* ecryptfs_msg_ctx_alloc_to_free
* @msg_ctx: The context to move from the alloc list to the free list
*
- * Be sure to lock the list mutex and the context mutex before
- * calling.
+ * Must be called with ecryptfs_msg_ctx_lists_mux held.
*/
-static void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
+void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)
{
list_move(&(msg_ctx->node), &ecryptfs_msg_ctx_free_list);
if (msg_ctx->msg)
kfree(msg_ctx->msg);
+ msg_ctx->msg = NULL;
msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;
}
/**
- * ecryptfs_find_daemon_id
- * @uid: The user id which maps to the desired daemon id
- * @id: If return value is zero, points to the desired daemon id
- * pointer
+ * ecryptfs_find_daemon_by_euid
+ * @euid: The effective user id which maps to the desired daemon id
+ * @user_ns: The namespace in which @euid applies
+ * @daemon: If return value is zero, points to the desired daemon pointer
*
- * Search the hash list for the given user id. Returns zero if the
- * user id exists in the list; non-zero otherwise. The daemon id hash
- * mutex should be held before calling this function.
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Search the hash list for the given user id.
+ *
+ * Returns zero if the user id exists in the list; non-zero otherwise.
*/
-static int ecryptfs_find_daemon_id(uid_t uid, struct ecryptfs_daemon_id **id)
+int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns)
{
struct hlist_node *elem;
int rc;
- hlist_for_each_entry(*id, elem,
- &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)],
- id_chain) {
- if ((*id)->uid == uid) {
+ hlist_for_each_entry(*daemon, elem,
+ &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],
+ euid_chain) {
+ if ((*daemon)->euid == euid && (*daemon)->user_ns == user_ns) {
rc = 0;
goto out;
}
@@ -128,181 +133,325 @@ out:
return rc;
}
-static int ecryptfs_send_raw_message(unsigned int transport, u16 msg_type,
- pid_t pid)
+static int
+ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
+ u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx);
+
+/**
+ * ecryptfs_send_raw_message
+ * @transport: Transport type
+ * @msg_type: Message type
+ * @daemon: Daemon struct for recipient of message
+ *
+ * A raw message is one that does not include an ecryptfs_message
+ * struct. It simply has a type.
+ *
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_send_raw_message(unsigned int transport, u8 msg_type,
+ struct ecryptfs_daemon *daemon)
{
+ struct ecryptfs_msg_ctx *msg_ctx;
int rc;
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0, pid);
+ rc = ecryptfs_send_netlink(NULL, 0, NULL, msg_type, 0,
+ daemon->pid);
+ break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ rc = ecryptfs_send_message_locked(transport, NULL, 0, msg_type,
+ &msg_ctx);
+ if (rc) {
+ printk(KERN_ERR "%s: Error whilst attempting to send "
+ "message via procfs; rc = [%d]\n", __func__, rc);
+ goto out;
+ }
+ /* Raw messages are logically context-free (e.g., no
+ * reply is expected), so we set the state of the
+ * ecryptfs_msg_ctx object to indicate that it should
+ * be freed as soon as the transport sends out the message. */
+ mutex_lock(&msg_ctx->mux);
+ msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_NO_REPLY;
+ mutex_unlock(&msg_ctx->mux);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_spawn_daemon - Create and initialize a new daemon struct
+ * @daemon: Pointer to set to newly allocated daemon struct
+ * @euid: Effective user id for the daemon
+ * @user_ns: The namespace in which @euid applies
+ * @pid: Process id for the daemon
+ *
+ * Must be called ceremoniously while in possession of
+ * ecryptfs_sacred_daemon_hash_mux
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int
+ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid)
+{
+ int rc = 0;
+
+ (*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);
+ if (!(*daemon)) {
+ rc = -ENOMEM;
+ printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
+ "GFP_KERNEL memory\n", __func__, sizeof(**daemon));
+ goto out;
+ }
+ (*daemon)->euid = euid;
+ (*daemon)->user_ns = get_user_ns(user_ns);
+ (*daemon)->pid = get_pid(pid);
+ (*daemon)->task = current;
+ mutex_init(&(*daemon)->mux);
+ INIT_LIST_HEAD(&(*daemon)->msg_ctx_out_queue);
+ init_waitqueue_head(&(*daemon)->wait);
+ (*daemon)->num_queued_msg_ctx = 0;
+ hlist_add_head(&(*daemon)->euid_chain,
+ &ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);
+out:
return rc;
}
/**
* ecryptfs_process_helo
* @transport: The underlying transport (netlink, etc.)
- * @uid: The user ID owner of the message
+ * @euid: The user ID owner of the message
+ * @user_ns: The namespace in which @euid applies
* @pid: The process ID for the userspace program that sent the
* message
*
- * Adds the uid and pid values to the daemon id hash. If a uid
+ * Adds the euid and pid values to the daemon euid hash. If an euid
* already has a daemon pid registered, the daemon will be
- * unregistered before the new daemon id is put into the hash list.
- * Returns zero after adding a new daemon id to the hash list;
+ * unregistered before the new daemon is put into the hash list.
+ * Returns zero after adding a new daemon to the hash list;
* non-zero otherwise.
*/
-int ecryptfs_process_helo(unsigned int transport, uid_t uid, pid_t pid)
+int ecryptfs_process_helo(unsigned int transport, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid)
{
- struct ecryptfs_daemon_id *new_id;
- struct ecryptfs_daemon_id *old_id;
+ struct ecryptfs_daemon *new_daemon;
+ struct ecryptfs_daemon *old_daemon;
int rc;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
- new_id = kmalloc(sizeof(*new_id), GFP_KERNEL);
- if (!new_id) {
- rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory; unable "
- "to register daemon [%d] for user [%d]\n",
- pid, uid);
- goto unlock;
- }
- if (!ecryptfs_find_daemon_id(uid, &old_id)) {
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&old_daemon, euid, user_ns);
+ if (rc != 0) {
printk(KERN_WARNING "Received request from user [%d] "
- "to register daemon [%d]; unregistering daemon "
- "[%d]\n", uid, pid, old_id->pid);
- hlist_del(&old_id->id_chain);
- rc = ecryptfs_send_raw_message(transport, ECRYPTFS_NLMSG_QUIT,
- old_id->pid);
+ "to register daemon [0x%p]; unregistering daemon "
+ "[0x%p]\n", euid, pid, old_daemon->pid);
+ rc = ecryptfs_send_raw_message(transport, ECRYPTFS_MSG_QUIT,
+ old_daemon);
if (rc)
printk(KERN_WARNING "Failed to send QUIT "
- "message to daemon [%d]; rc = [%d]\n",
- old_id->pid, rc);
- kfree(old_id);
+ "message to daemon [0x%p]; rc = [%d]\n",
+ old_daemon->pid, rc);
+ hlist_del(&old_daemon->euid_chain);
+ kfree(old_daemon);
}
- new_id->uid = uid;
- new_id->pid = pid;
- hlist_add_head(&new_id->id_chain,
- &ecryptfs_daemon_id_hash[ecryptfs_uid_hash(uid)]);
- rc = 0;
-unlock:
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ rc = ecryptfs_spawn_daemon(&new_daemon, euid, user_ns, pid);
+ if (rc)
+ printk(KERN_ERR "%s: The gods are displeased with this attempt "
+ "to create a new daemon object for euid [%d]; pid "
+ "[0x%p]; rc = [%d]\n", __func__, euid, pid, rc);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_exorcise_daemon - Destroy the daemon struct
+ *
+ * Must be called ceremoniously while in possession of
+ * ecryptfs_daemon_hash_mux and the daemon's own mux.
+ */
+int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)
+{
+ struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;
+ int rc = 0;
+
+ mutex_lock(&daemon->mux);
+ if ((daemon->flags & ECRYPTFS_DAEMON_IN_READ)
+ || (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)) {
+ rc = -EBUSY;
+ printk(KERN_WARNING "%s: Attempt to destroy daemon with pid "
+ "[0x%p], but it is in the midst of a read or a poll\n",
+ __func__, daemon->pid);
+ mutex_unlock(&daemon->mux);
+ goto out;
+ }
+ list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,
+ &daemon->msg_ctx_out_queue, daemon_out_list) {
+ list_del(&msg_ctx->daemon_out_list);
+ daemon->num_queued_msg_ctx--;
+ printk(KERN_WARNING "%s: Warning: dropping message that is in "
+ "the out queue of a dying daemon\n", __func__);
+ ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
+ }
+ hlist_del(&daemon->euid_chain);
+ if (daemon->task)
+ wake_up_process(daemon->task);
+ if (daemon->pid)
+ put_pid(daemon->pid);
+ if (daemon->user_ns)
+ put_user_ns(daemon->user_ns);
+ mutex_unlock(&daemon->mux);
+ memset(daemon, 0, sizeof(*daemon));
+ kfree(daemon);
+out:
return rc;
}
/**
* ecryptfs_process_quit
- * @uid: The user ID owner of the message
+ * @euid: The user ID owner of the message
+ * @user_ns: The namespace in which @euid applies
* @pid: The process ID for the userspace program that sent the
* message
*
- * Deletes the corresponding daemon id for the given uid and pid, if
+ * Deletes the corresponding daemon for the given euid and pid, if
* it is the registered that is requesting the deletion. Returns zero
- * after deleting the desired daemon id; non-zero otherwise.
+ * after deleting the desired daemon; non-zero otherwise.
*/
-int ecryptfs_process_quit(uid_t uid, pid_t pid)
+int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
{
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
int rc;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
- if (ecryptfs_find_daemon_id(uid, &id)) {
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, euid, user_ns);
+ if (rc || !daemon) {
rc = -EINVAL;
- ecryptfs_printk(KERN_ERR, "Received request from user [%d] to "
- "unregister unrecognized daemon [%d]\n", uid,
- pid);
- goto unlock;
+ printk(KERN_ERR "Received request from user [%d] to "
+ "unregister unrecognized daemon [0x%p]\n", euid, pid);
+ goto out_unlock;
}
- if (id->pid != pid) {
- rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Received request from user [%d] "
- "with pid [%d] to unregister daemon [%d]\n",
- uid, pid, id->pid);
- goto unlock;
- }
- hlist_del(&id->id_chain);
- kfree(id);
- rc = 0;
-unlock:
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ rc = ecryptfs_exorcise_daemon(daemon);
+out_unlock:
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
return rc;
}
/**
* ecryptfs_process_reponse
* @msg: The ecryptfs message received; the caller should sanity check
- * msg->data_len
+ * msg->data_len and free the memory
* @pid: The process ID of the userspace application that sent the
* message
- * @seq: The sequence number of the message
+ * @seq: The sequence number of the message; must match the sequence
+ * number for the existing message context waiting for this
+ * response
+ *
+ * Processes a response message after sending an operation request to
+ * userspace. Some other process is awaiting this response. Before
+ * sending out its first communications, the other process allocated a
+ * msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The
+ * response message contains this index so that we can copy over the
+ * response message into the msg_ctx that the process holds a
+ * reference to. The other process is going to wake up, check to see
+ * that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then
+ * proceed to read off and process the response message. Returns zero
+ * upon delivery to desired context element; non-zero upon delivery
+ * failure or error.
*
- * Processes a response message after sending a operation request to
- * userspace. Returns zero upon delivery to desired context element;
- * non-zero upon delivery failure or error.
+ * Returns zero on success; non-zero otherwise
*/
-int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t uid,
- pid_t pid, u32 seq)
+int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,
+ struct user_namespace *user_ns, struct pid *pid,
+ u32 seq)
{
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
struct ecryptfs_msg_ctx *msg_ctx;
- int msg_size;
+ size_t msg_size;
+ struct nsproxy *nsproxy;
+ struct user_namespace *current_user_ns;
int rc;
if (msg->index >= ecryptfs_message_buf_len) {
rc = -EINVAL;
- ecryptfs_printk(KERN_ERR, "Attempt to reference "
- "context buffer at index [%d]; maximum "
- "allowable is [%d]\n", msg->index,
- (ecryptfs_message_buf_len - 1));
+ printk(KERN_ERR "%s: Attempt to reference "
+ "context buffer at index [%d]; maximum "
+ "allowable is [%d]\n", __func__, msg->index,
+ (ecryptfs_message_buf_len - 1));
goto out;
}
msg_ctx = &ecryptfs_msg_ctx_arr[msg->index];
mutex_lock(&msg_ctx->mux);
- if (ecryptfs_find_daemon_id(msg_ctx->task->euid, &id)) {
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rcu_read_lock();
+ nsproxy = task_nsproxy(msg_ctx->task);
+ if (nsproxy == NULL) {
rc = -EBADMSG;
- ecryptfs_printk(KERN_WARNING, "User [%d] received a "
- "message response from process [%d] but does "
- "not have a registered daemon\n",
- msg_ctx->task->euid, pid);
+ printk(KERN_ERR "%s: Receiving process is a zombie. Dropping "
+ "message.\n", __func__);
+ rcu_read_unlock();
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
goto wake_up;
}
- if (msg_ctx->task->euid != uid) {
+ current_user_ns = nsproxy->user_ns;
+ rc = ecryptfs_find_daemon_by_euid(&daemon, msg_ctx->task->euid,
+ current_user_ns);
+ rcu_read_unlock();
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ if (rc) {
+ rc = -EBADMSG;
+ printk(KERN_WARNING "%s: User [%d] received a "
+ "message response from process [0x%p] but does "
+ "not have a registered daemon\n", __func__,
+ msg_ctx->task->euid, pid);
+ goto wake_up;
+ }
+ if (msg_ctx->task->euid != euid) {
rc = -EBADMSG;
- ecryptfs_printk(KERN_WARNING, "Received message from user "
- "[%d]; expected message from user [%d]\n",
- uid, msg_ctx->task->euid);
+ printk(KERN_WARNING "%s: Received message from user "
+ "[%d]; expected message from user [%d]\n", __func__,
+ euid, msg_ctx->task->euid);
goto unlock;
}
- if (id->pid != pid) {
+ if (current_user_ns != user_ns) {
rc = -EBADMSG;
- ecryptfs_printk(KERN_ERR, "User [%d] received a "
- "message response from an unrecognized "
- "process [%d]\n", msg_ctx->task->euid, pid);
+ printk(KERN_WARNING "%s: Received message from user_ns "
+ "[0x%p]; expected message from user_ns [0x%p]\n",
+ __func__, user_ns, nsproxy->user_ns);
+ goto unlock;
+ }
+ if (daemon->pid != pid) {
+ rc = -EBADMSG;
+ printk(KERN_ERR "%s: User [%d] sent a message response "
+ "from an unrecognized process [0x%p]\n",
+ __func__, msg_ctx->task->euid, pid);
goto unlock;
}
if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Desired context element is not "
- "pending a response\n");
+ printk(KERN_WARNING "%s: Desired context element is not "
+ "pending a response\n", __func__);
goto unlock;
} else if (msg_ctx->counter != seq) {
rc = -EINVAL;
- ecryptfs_printk(KERN_WARNING, "Invalid message sequence; "
- "expected [%d]; received [%d]\n",
- msg_ctx->counter, seq);
+ printk(KERN_WARNING "%s: Invalid message sequence; "
+ "expected [%d]; received [%d]\n", __func__,
+ msg_ctx->counter, seq);
goto unlock;
}
- msg_size = sizeof(*msg) + msg->data_len;
+ msg_size = (sizeof(*msg) + msg->data_len);
msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);
if (!msg_ctx->msg) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
+ printk(KERN_ERR "%s: Failed to allocate [%Zd] bytes of "
+ "GFP_KERNEL memory\n", __func__, msg_size);
goto unlock;
}
memcpy(msg_ctx->msg, msg, msg_size);
@@ -317,34 +466,38 @@ out:
}
/**
- * ecryptfs_send_message
+ * ecryptfs_send_message_locked
* @transport: The transport over which to send the message (i.e.,
* netlink)
* @data: The data to send
* @data_len: The length of data
* @msg_ctx: The message context allocated for the send
+ *
+ * Must be called with ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
*/
-int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
- struct ecryptfs_msg_ctx **msg_ctx)
+static int
+ecryptfs_send_message_locked(unsigned int transport, char *data, int data_len,
+ u8 msg_type, struct ecryptfs_msg_ctx **msg_ctx)
{
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
int rc;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
- if (ecryptfs_find_daemon_id(current->euid, &id)) {
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ if (rc || !daemon) {
rc = -ENOTCONN;
- ecryptfs_printk(KERN_ERR, "User [%d] does not have a daemon "
- "registered\n", current->euid);
+ printk(KERN_ERR "%s: User [%d] does not have a daemon "
+ "registered\n", __func__, current->euid);
goto out;
}
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
mutex_lock(&ecryptfs_msg_ctx_lists_mux);
rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);
if (rc) {
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
- ecryptfs_printk(KERN_WARNING, "Could not claim a free "
- "context element\n");
+ printk(KERN_WARNING "%s: Could not claim a free "
+ "context element\n", __func__);
goto out;
}
ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);
@@ -352,23 +505,50 @@ int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
switch (transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
- rc = ecryptfs_send_netlink(data, data_len, *msg_ctx,
- ECRYPTFS_NLMSG_REQUEST, 0, id->pid);
+ rc = ecryptfs_send_netlink(data, data_len, *msg_ctx, msg_type,
+ 0, daemon->pid);
+ break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type,
+ 0, daemon);
break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
rc = -ENOSYS;
}
- if (rc) {
- printk(KERN_ERR "Error attempting to send message to userspace "
- "daemon; rc = [%d]\n", rc);
- }
+ if (rc)
+ printk(KERN_ERR "%s: Error attempting to send message to "
+ "userspace daemon; rc = [%d]\n", __func__, rc);
out:
return rc;
}
/**
+ * ecryptfs_send_message
+ * @transport: The transport over which to send the message (i.e.,
+ * netlink)
+ * @data: The data to send
+ * @data_len: The length of data
+ * @msg_ctx: The message context allocated for the send
+ *
+ * Grabs ecryptfs_daemon_hash_mux.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_send_message(unsigned int transport, char *data, int data_len,
+ struct ecryptfs_msg_ctx **msg_ctx)
+{
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_send_message_locked(transport, data, data_len,
+ ECRYPTFS_MSG_REQUEST, msg_ctx);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
* ecryptfs_wait_for_response
* @msg_ctx: The context that was assigned when sending a message
* @msg: The incoming message from userspace; not set if rc != 0
@@ -377,7 +557,7 @@ out:
* of time exceeds ecryptfs_message_wait_timeout. If zero is
* returned, msg will point to a valid message from userspace; a
* non-zero value is returned upon failure to receive a message or an
- * error occurs.
+ * error occurs. Callee must free @msg on success.
*/
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,
struct ecryptfs_message **msg)
@@ -413,32 +593,32 @@ int ecryptfs_init_messaging(unsigned int transport)
if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {
ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;
- ecryptfs_printk(KERN_WARNING, "Specified number of users is "
- "too large, defaulting to [%d] users\n",
- ecryptfs_number_of_users);
+ printk(KERN_WARNING "%s: Specified number of users is "
+ "too large, defaulting to [%d] users\n", __func__,
+ ecryptfs_number_of_users);
}
- mutex_init(&ecryptfs_daemon_id_hash_mux);
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
+ mutex_init(&ecryptfs_daemon_hash_mux);
+ mutex_lock(&ecryptfs_daemon_hash_mux);
ecryptfs_hash_buckets = 1;
while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)
ecryptfs_hash_buckets++;
- ecryptfs_daemon_id_hash = kmalloc(sizeof(struct hlist_head)
- * ecryptfs_hash_buckets, GFP_KERNEL);
- if (!ecryptfs_daemon_id_hash) {
+ ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)
+ * ecryptfs_hash_buckets), GFP_KERNEL);
+ if (!ecryptfs_daemon_hash) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
goto out;
}
for (i = 0; i < ecryptfs_hash_buckets; i++)
- INIT_HLIST_HEAD(&ecryptfs_daemon_id_hash[i]);
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
-
+ INIT_HLIST_HEAD(&ecryptfs_daemon_hash[i]);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)
- * ecryptfs_message_buf_len), GFP_KERNEL);
+ * ecryptfs_message_buf_len),
+ GFP_KERNEL);
if (!ecryptfs_msg_ctx_arr) {
rc = -ENOMEM;
- ecryptfs_printk(KERN_ERR, "Failed to allocate memory\n");
+ printk(KERN_ERR "%s: Failed to allocate memory\n", __func__);
goto out;
}
mutex_init(&ecryptfs_msg_ctx_lists_mux);
@@ -446,6 +626,7 @@ int ecryptfs_init_messaging(unsigned int transport)
ecryptfs_msg_counter = 0;
for (i = 0; i < ecryptfs_message_buf_len; i++) {
INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].node);
+ INIT_LIST_HEAD(&ecryptfs_msg_ctx_arr[i].daemon_out_list);
mutex_init(&ecryptfs_msg_ctx_arr[i].mux);
mutex_lock(&ecryptfs_msg_ctx_arr[i].mux);
ecryptfs_msg_ctx_arr[i].index = i;
@@ -464,6 +645,11 @@ int ecryptfs_init_messaging(unsigned int transport)
if (rc)
ecryptfs_release_messaging(transport);
break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ rc = ecryptfs_init_ecryptfs_miscdev();
+ if (rc)
+ ecryptfs_release_messaging(transport);
+ break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
@@ -488,27 +674,37 @@ void ecryptfs_release_messaging(unsigned int transport)
kfree(ecryptfs_msg_ctx_arr);
mutex_unlock(&ecryptfs_msg_ctx_lists_mux);
}
- if (ecryptfs_daemon_id_hash) {
+ if (ecryptfs_daemon_hash) {
struct hlist_node *elem;
- struct ecryptfs_daemon_id *id;
+ struct ecryptfs_daemon *daemon;
int i;
- mutex_lock(&ecryptfs_daemon_id_hash_mux);
+ mutex_lock(&ecryptfs_daemon_hash_mux);
for (i = 0; i < ecryptfs_hash_buckets; i++) {
- hlist_for_each_entry(id, elem,
- &ecryptfs_daemon_id_hash[i],
- id_chain) {
- hlist_del(elem);
- kfree(id);
+ int rc;
+
+ hlist_for_each_entry(daemon, elem,
+ &ecryptfs_daemon_hash[i],
+ euid_chain) {
+ rc = ecryptfs_exorcise_daemon(daemon);
+ if (rc)
+ printk(KERN_ERR "%s: Error whilst "
+ "attempting to destroy daemon; "
+ "rc = [%d]. Dazed and confused, "
+ "but trying to continue.\n",
+ __func__, rc);
}
}
- kfree(ecryptfs_daemon_id_hash);
- mutex_unlock(&ecryptfs_daemon_id_hash_mux);
+ kfree(ecryptfs_daemon_hash);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
}
switch(transport) {
case ECRYPTFS_TRANSPORT_NETLINK:
ecryptfs_release_netlink();
break;
+ case ECRYPTFS_TRANSPORT_MISCDEV:
+ ecryptfs_destroy_ecryptfs_miscdev();
+ break;
case ECRYPTFS_TRANSPORT_CONNECTOR:
case ECRYPTFS_TRANSPORT_RELAYFS:
default:
diff --git a/fs/ecryptfs/miscdev.c b/fs/ecryptfs/miscdev.c
new file mode 100644
index 000000000000..788995efd1d3
--- /dev/null
+++ b/fs/ecryptfs/miscdev.c
@@ -0,0 +1,598 @@
+/**
+ * eCryptfs: Linux filesystem encryption layer
+ *
+ * Copyright (C) 2008 International Business Machines Corp.
+ * Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+ * 02111-1307, USA.
+ */
+
+#include <linux/fs.h>
+#include <linux/hash.h>
+#include <linux/random.h>
+#include <linux/miscdevice.h>
+#include <linux/poll.h>
+#include <linux/wait.h>
+#include <linux/module.h>
+#include "ecryptfs_kernel.h"
+
+static atomic_t ecryptfs_num_miscdev_opens;
+
+/**
+ * ecryptfs_miscdev_poll
+ * @file: dev file (ignored)
+ * @pt: dev poll table (ignored)
+ *
+ * Returns the poll mask
+ */
+static unsigned int
+ecryptfs_miscdev_poll(struct file *file, poll_table *pt)
+{
+ struct ecryptfs_daemon *daemon;
+ unsigned int mask = 0;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ /* TODO: Just use file->private_data? */
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ BUG_ON(rc || !daemon);
+ mutex_lock(&daemon->mux);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
+ printk(KERN_WARNING "%s: Attempt to poll on zombified "
+ "daemon\n", __func__);
+ goto out_unlock_daemon;
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_IN_READ)
+ goto out_unlock_daemon;
+ if (daemon->flags & ECRYPTFS_DAEMON_IN_POLL)
+ goto out_unlock_daemon;
+ daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;
+ mutex_unlock(&daemon->mux);
+ poll_wait(file, &daemon->wait, pt);
+ mutex_lock(&daemon->mux);
+ if (!list_empty(&daemon->msg_ctx_out_queue))
+ mask |= POLLIN | POLLRDNORM;
+out_unlock_daemon:
+ daemon->flags &= ~ECRYPTFS_DAEMON_IN_POLL;
+ mutex_unlock(&daemon->mux);
+ return mask;
+}
+
+/**
+ * ecryptfs_miscdev_open
+ * @inode: inode of miscdev handle (ignored)
+ * @file: file for miscdev handle (ignored)
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_miscdev_open(struct inode *inode, struct file *file)
+{
+ struct ecryptfs_daemon *daemon = NULL;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = try_module_get(THIS_MODULE);
+ if (rc == 0) {
+ rc = -EIO;
+ printk(KERN_ERR "%s: Error attempting to increment module use "
+ "count; rc = [%d]\n", __func__, rc);
+ goto out_unlock_daemon_list;
+ }
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ if (rc || !daemon) {
+ rc = ecryptfs_spawn_daemon(&daemon, current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current));
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to spawn daemon; "
+ "rc = [%d]\n", __func__, rc);
+ goto out_module_put_unlock_daemon_list;
+ }
+ }
+ mutex_lock(&daemon->mux);
+ if (daemon->pid != task_pid(current)) {
+ rc = -EINVAL;
+ printk(KERN_ERR "%s: pid [0x%p] has registered with euid [%d], "
+ "but pid [0x%p] has attempted to open the handle "
+ "instead\n", __func__, daemon->pid, daemon->euid,
+ task_pid(current));
+ goto out_unlock_daemon;
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN) {
+ rc = -EBUSY;
+ printk(KERN_ERR "%s: Miscellaneous device handle may only be "
+ "opened once per daemon; pid [0x%p] already has this "
+ "handle open\n", __func__, daemon->pid);
+ goto out_unlock_daemon;
+ }
+ daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;
+ atomic_inc(&ecryptfs_num_miscdev_opens);
+out_unlock_daemon:
+ mutex_unlock(&daemon->mux);
+out_module_put_unlock_daemon_list:
+ if (rc)
+ module_put(THIS_MODULE);
+out_unlock_daemon_list:
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_release
+ * @inode: inode of fs/ecryptfs/euid handle (ignored)
+ * @file: file for fs/ecryptfs/euid handle (ignored)
+ *
+ * This keeps the daemon registered until the daemon sends another
+ * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int
+ecryptfs_miscdev_release(struct inode *inode, struct file *file)
+{
+ struct ecryptfs_daemon *daemon = NULL;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ BUG_ON(rc || !daemon);
+ mutex_lock(&daemon->mux);
+ BUG_ON(daemon->pid != task_pid(current));
+ BUG_ON(!(daemon->flags & ECRYPTFS_DAEMON_MISCDEV_OPEN));
+ daemon->flags &= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;
+ atomic_dec(&ecryptfs_num_miscdev_opens);
+ mutex_unlock(&daemon->mux);
+ rc = ecryptfs_exorcise_daemon(daemon);
+ if (rc) {
+ printk(KERN_CRIT "%s: Fatal error whilst attempting to "
+ "shut down daemon; rc = [%d]. Please report this "
+ "bug.\n", __func__, rc);
+ BUG();
+ }
+ module_put(THIS_MODULE);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_send_miscdev
+ * @data: Data to send to daemon; may be NULL
+ * @data_size: Amount of data to send to daemon
+ * @msg_ctx: Message context, which is used to handle the reply. If
+ * this is NULL, then we do not expect a reply.
+ * @msg_type: Type of message
+ * @msg_flags: Flags for message
+ * @daemon: eCryptfs daemon object
+ *
+ * Add msg_ctx to queue and then, if it exists, notify the blocked
+ * miscdevess about the data being available. Must be called with
+ * ecryptfs_daemon_hash_mux held.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_send_miscdev(char *data, size_t data_size,
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct ecryptfs_daemon *daemon)
+{
+ int rc = 0;
+
+ mutex_lock(&msg_ctx->mux);
+ if (data) {
+ msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),
+ GFP_KERNEL);
+ if (!msg_ctx->msg) {
+ rc = -ENOMEM;
+ printk(KERN_ERR "%s: Out of memory whilst attempting "
+ "to kmalloc(%Zd, GFP_KERNEL)\n", __func__,
+ (sizeof(*msg_ctx->msg) + data_size));
+ goto out_unlock;
+ }
+ } else
+ msg_ctx->msg = NULL;
+ msg_ctx->msg->index = msg_ctx->index;
+ msg_ctx->msg->data_len = data_size;
+ msg_ctx->type = msg_type;
+ if (data) {
+ memcpy(msg_ctx->msg->data, data, data_size);
+ msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);
+ } else
+ msg_ctx->msg_size = 0;
+ mutex_lock(&daemon->mux);
+ list_add_tail(&msg_ctx->daemon_out_list, &daemon->msg_ctx_out_queue);
+ daemon->num_queued_msg_ctx++;
+ wake_up_interruptible(&daemon->wait);
+ mutex_unlock(&daemon->mux);
+out_unlock:
+ mutex_unlock(&msg_ctx->mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_read - format and send message from queue
+ * @file: fs/ecryptfs/euid miscdevfs handle (ignored)
+ * @buf: User buffer into which to copy the next message on the daemon queue
+ * @count: Amount of space available in @buf
+ * @ppos: Offset in file (ignored)
+ *
+ * Pulls the most recent message from the daemon queue, formats it for
+ * being sent via a miscdevfs handle, and copies it into @buf
+ *
+ * Returns the number of bytes copied into the user buffer
+ */
+static ssize_t
+ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,
+ loff_t *ppos)
+{
+ struct ecryptfs_daemon *daemon;
+ struct ecryptfs_msg_ctx *msg_ctx;
+ size_t packet_length_size;
+ u32 counter_nbo;
+ char packet_length[3];
+ size_t i;
+ size_t total_length;
+ int rc;
+
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ /* TODO: Just use file->private_data? */
+ rc = ecryptfs_find_daemon_by_euid(&daemon, current->euid,
+ current->nsproxy->user_ns);
+ BUG_ON(rc || !daemon);
+ mutex_lock(&daemon->mux);
+ if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
+ rc = 0;
+ printk(KERN_WARNING "%s: Attempt to read from zombified "
+ "daemon\n", __func__);
+ goto out_unlock_daemon;
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_IN_READ) {
+ rc = 0;
+ goto out_unlock_daemon;
+ }
+ /* This daemon will not go away so long as this flag is set */
+ daemon->flags |= ECRYPTFS_DAEMON_IN_READ;
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+check_list:
+ if (list_empty(&daemon->msg_ctx_out_queue)) {
+ mutex_unlock(&daemon->mux);
+ rc = wait_event_interruptible(
+ daemon->wait, !list_empty(&daemon->msg_ctx_out_queue));
+ mutex_lock(&daemon->mux);
+ if (rc < 0) {
+ rc = 0;
+ goto out_unlock_daemon;
+ }
+ }
+ if (daemon->flags & ECRYPTFS_DAEMON_ZOMBIE) {
+ rc = 0;
+ goto out_unlock_daemon;
+ }
+ if (list_empty(&daemon->msg_ctx_out_queue)) {
+ /* Something else jumped in since the
+ * wait_event_interruptable() and removed the
+ * message from the queue; try again */
+ goto check_list;
+ }
+ BUG_ON(current->euid != daemon->euid);
+ BUG_ON(current->nsproxy->user_ns != daemon->user_ns);
+ BUG_ON(task_pid(current) != daemon->pid);
+ msg_ctx = list_first_entry(&daemon->msg_ctx_out_queue,
+ struct ecryptfs_msg_ctx, daemon_out_list);
+ BUG_ON(!msg_ctx);
+ mutex_lock(&msg_ctx->mux);
+ if (msg_ctx->msg) {
+ rc = ecryptfs_write_packet_length(packet_length,
+ msg_ctx->msg_size,
+ &packet_length_size);
+ if (rc) {
+ rc = 0;
+ printk(KERN_WARNING "%s: Error writing packet length; "
+ "rc = [%d]\n", __func__, rc);
+ goto out_unlock_msg_ctx;
+ }
+ } else {
+ packet_length_size = 0;
+ msg_ctx->msg_size = 0;
+ }
+ /* miscdevfs packet format:
+ * Octet 0: Type
+ * Octets 1-4: network byte order msg_ctx->counter
+ * Octets 5-N0: Size of struct ecryptfs_message to follow
+ * Octets N0-N1: struct ecryptfs_message (including data)
+ *
+ * Octets 5-N1 not written if the packet type does not
+ * include a message */
+ total_length = (1 + 4 + packet_length_size + msg_ctx->msg_size);
+ if (count < total_length) {
+ rc = 0;
+ printk(KERN_WARNING "%s: Only given user buffer of "
+ "size [%Zd], but we need [%Zd] to read the "
+ "pending message\n", __func__, count, total_length);
+ goto out_unlock_msg_ctx;
+ }
+ i = 0;
+ buf[i++] = msg_ctx->type;
+ counter_nbo = cpu_to_be32(msg_ctx->counter);
+ memcpy(&buf[i], (char *)&counter_nbo, 4);
+ i += 4;
+ if (msg_ctx->msg) {
+ memcpy(&buf[i], packet_length, packet_length_size);
+ i += packet_length_size;
+ rc = copy_to_user(&buf[i], msg_ctx->msg, msg_ctx->msg_size);
+ if (rc) {
+ printk(KERN_ERR "%s: copy_to_user returned error "
+ "[%d]\n", __func__, rc);
+ goto out_unlock_msg_ctx;
+ }
+ i += msg_ctx->msg_size;
+ }
+ rc = i;
+ list_del(&msg_ctx->daemon_out_list);
+ kfree(msg_ctx->msg);
+ msg_ctx->msg = NULL;
+ /* We do not expect a reply from the userspace daemon for any
+ * message type other than ECRYPTFS_MSG_REQUEST */
+ if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)
+ ecryptfs_msg_ctx_alloc_to_free(msg_ctx);
+out_unlock_msg_ctx:
+ mutex_unlock(&msg_ctx->mux);
+out_unlock_daemon:
+ daemon->flags &= ~ECRYPTFS_DAEMON_IN_READ;
+ mutex_unlock(&daemon->mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_helo
+ * @euid: effective user id of miscdevess sending helo packet
+ * @user_ns: The namespace in which @euid applies
+ * @pid: miscdevess id of miscdevess sending helo packet
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_miscdev_helo(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
+{
+ int rc;
+
+ rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_MISCDEV, euid, user_ns,
+ pid);
+ if (rc)
+ printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_quit
+ * @euid: effective user id of miscdevess sending quit packet
+ * @user_ns: The namespace in which @euid applies
+ * @pid: miscdevess id of miscdevess sending quit packet
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_miscdev_quit(uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid)
+{
+ int rc;
+
+ rc = ecryptfs_process_quit(euid, user_ns, pid);
+ if (rc)
+ printk(KERN_WARNING
+ "Error processing QUIT message; rc = [%d]\n", rc);
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_response - miscdevess response to message previously sent to daemon
+ * @data: Bytes comprising struct ecryptfs_message
+ * @data_size: sizeof(struct ecryptfs_message) + data len
+ * @euid: Effective user id of miscdevess sending the miscdev response
+ * @user_ns: The namespace in which @euid applies
+ * @pid: Miscdevess id of miscdevess sending the miscdev response
+ * @seq: Sequence number for miscdev response packet
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+static int ecryptfs_miscdev_response(char *data, size_t data_size,
+ uid_t euid, struct user_namespace *user_ns,
+ struct pid *pid, u32 seq)
+{
+ struct ecryptfs_message *msg = (struct ecryptfs_message *)data;
+ int rc;
+
+ if ((sizeof(*msg) + msg->data_len) != data_size) {
+ printk(KERN_WARNING "%s: (sizeof(*msg) + msg->data_len) = "
+ "[%Zd]; data_size = [%Zd]. Invalid packet.\n", __func__,
+ (sizeof(*msg) + msg->data_len), data_size);
+ rc = -EINVAL;
+ goto out;
+ }
+ rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq);
+ if (rc)
+ printk(KERN_ERR
+ "Error processing response message; rc = [%d]\n", rc);
+out:
+ return rc;
+}
+
+/**
+ * ecryptfs_miscdev_write - handle write to daemon miscdev handle
+ * @file: File for misc dev handle (ignored)
+ * @buf: Buffer containing user data
+ * @count: Amount of data in @buf
+ * @ppos: Pointer to offset in file (ignored)
+ *
+ * miscdevfs packet format:
+ * Octet 0: Type
+ * Octets 1-4: network byte order msg_ctx->counter (0's for non-response)
+ * Octets 5-N0: Size of struct ecryptfs_message to follow
+ * Octets N0-N1: struct ecryptfs_message (including data)
+ *
+ * Returns the number of bytes read from @buf
+ */
+static ssize_t
+ecryptfs_miscdev_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ u32 counter_nbo, seq;
+ size_t packet_size, packet_size_length, i;
+ ssize_t sz = 0;
+ char *data;
+ int rc;
+
+ if (count == 0)
+ goto out;
+ data = kmalloc(count, GFP_KERNEL);
+ if (!data) {
+ printk(KERN_ERR "%s: Out of memory whilst attempting to "
+ "kmalloc([%Zd], GFP_KERNEL)\n", __func__, count);
+ goto out;
+ }
+ rc = copy_from_user(data, buf, count);
+ if (rc) {
+ printk(KERN_ERR "%s: copy_from_user returned error [%d]\n",
+ __func__, rc);
+ goto out_free;
+ }
+ sz = count;
+ i = 0;
+ switch (data[i++]) {
+ case ECRYPTFS_MSG_RESPONSE:
+ if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) {
+ printk(KERN_WARNING "%s: Minimum acceptable packet "
+ "size is [%Zd], but amount of data written is "
+ "only [%Zd]. Discarding response packet.\n",
+ __func__,
+ (1 + 4 + 1 + sizeof(struct ecryptfs_message)),
+ count);
+ goto out_free;
+ }
+ memcpy((char *)&counter_nbo, &data[i], 4);
+ seq = be32_to_cpu(counter_nbo);
+ i += 4;
+ rc = ecryptfs_parse_packet_length(&data[i], &packet_size,
+ &packet_size_length);
+ if (rc) {
+ printk(KERN_WARNING "%s: Error parsing packet length; "
+ "rc = [%d]\n", __func__, rc);
+ goto out_free;
+ }
+ i += packet_size_length;
+ if ((1 + 4 + packet_size_length + packet_size) != count) {
+ printk(KERN_WARNING "%s: (1 + packet_size_length([%Zd])"
+ " + packet_size([%Zd]))([%Zd]) != "
+ "count([%Zd]). Invalid packet format.\n",
+ __func__, packet_size_length, packet_size,
+ (1 + packet_size_length + packet_size), count);
+ goto out_free;
+ }
+ rc = ecryptfs_miscdev_response(&data[i], packet_size,
+ current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current), seq);
+ if (rc)
+ printk(KERN_WARNING "%s: Failed to deliver miscdev "
+ "response to requesting operation; rc = [%d]\n",
+ __func__, rc);
+ break;
+ case ECRYPTFS_MSG_HELO:
+ rc = ecryptfs_miscdev_helo(current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current));
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to process "
+ "helo from pid [0x%p]; rc = [%d]\n", __func__,
+ task_pid(current), rc);
+ goto out_free;
+ }
+ break;
+ case ECRYPTFS_MSG_QUIT:
+ rc = ecryptfs_miscdev_quit(current->euid,
+ current->nsproxy->user_ns,
+ task_pid(current));
+ if (rc) {
+ printk(KERN_ERR "%s: Error attempting to process "
+ "quit from pid [0x%p]; rc = [%d]\n", __func__,
+ task_pid(current), rc);
+ goto out_free;
+ }
+ break;
+ default:
+ ecryptfs_printk(KERN_WARNING, "Dropping miscdev "
+ "message of unrecognized type [%d]\n",
+ data[0]);
+ break;
+ }
+out_free:
+ kfree(data);
+out:
+ return sz;
+}
+
+
+static const struct file_operations ecryptfs_miscdev_fops = {
+ .open = ecryptfs_miscdev_open,
+ .poll = ecryptfs_miscdev_poll,
+ .read = ecryptfs_miscdev_read,
+ .write = ecryptfs_miscdev_write,
+ .release = ecryptfs_miscdev_release,
+};
+
+static struct miscdevice ecryptfs_miscdev = {
+ .minor = MISC_DYNAMIC_MINOR,
+ .name = "ecryptfs",
+ .fops = &ecryptfs_miscdev_fops
+};
+
+/**
+ * ecryptfs_init_ecryptfs_miscdev
+ *
+ * Messages sent to the userspace daemon from the kernel are placed on
+ * a queue associated with the daemon. The next read against the
+ * miscdev handle by that daemon will return the oldest message placed
+ * on the message queue for the daemon.
+ *
+ * Returns zero on success; non-zero otherwise
+ */
+int ecryptfs_init_ecryptfs_miscdev(void)
+{
+ int rc;
+
+ atomic_set(&ecryptfs_num_miscdev_opens, 0);
+ mutex_lock(&ecryptfs_daemon_hash_mux);
+ rc = misc_register(&ecryptfs_miscdev);
+ if (rc)
+ printk(KERN_ERR "%s: Failed to register miscellaneous device "
+ "for communications with userspace daemons; rc = [%d]\n",
+ __func__, rc);
+ mutex_unlock(&ecryptfs_daemon_hash_mux);
+ return rc;
+}
+
+/**
+ * ecryptfs_destroy_ecryptfs_miscdev
+ *
+ * All of the daemons must be exorcised prior to calling this
+ * function.
+ */
+void ecryptfs_destroy_ecryptfs_miscdev(void)
+{
+ BUG_ON(atomic_read(&ecryptfs_num_miscdev_opens) != 0);
+ misc_deregister(&ecryptfs_miscdev);
+}
diff --git a/fs/ecryptfs/mmap.c b/fs/ecryptfs/mmap.c
index 6df1debdccce..2b6fe1e6e8ba 100644
--- a/fs/ecryptfs/mmap.c
+++ b/fs/ecryptfs/mmap.c
@@ -153,7 +153,7 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
flush_dcache_page(page);
if (rc) {
printk(KERN_ERR "%s: Error reading xattr "
- "region; rc = [%d]\n", __FUNCTION__, rc);
+ "region; rc = [%d]\n", __func__, rc);
goto out;
}
} else {
@@ -169,7 +169,7 @@ ecryptfs_copy_up_encrypted_with_header(struct page *page,
if (rc) {
printk(KERN_ERR "%s: Error attempting to read "
"extent at offset [%lld] in the lower "
- "file; rc = [%d]\n", __FUNCTION__,
+ "file; rc = [%d]\n", __func__,
lower_offset, rc);
goto out;
}
@@ -212,7 +212,7 @@ static int ecryptfs_readpage(struct file *file, struct page *page)
"the encrypted content from the lower "
"file whilst inserting the metadata "
"from the xattr into the header; rc = "
- "[%d]\n", __FUNCTION__, rc);
+ "[%d]\n", __func__, rc);
goto out;
}
@@ -293,7 +293,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (rc) {
printk(KERN_ERR "%s: Error attemping to read "
"lower page segment; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
ClearPageUptodate(page);
goto out;
} else
@@ -308,7 +308,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
"from the lower file whilst "
"inserting the metadata from "
"the xattr into the header; rc "
- "= [%d]\n", __FUNCTION__, rc);
+ "= [%d]\n", __func__, rc);
ClearPageUptodate(page);
goto out;
}
@@ -320,7 +320,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (rc) {
printk(KERN_ERR "%s: Error reading "
"page; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
ClearPageUptodate(page);
goto out;
}
@@ -331,7 +331,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (rc) {
printk(KERN_ERR "%s: Error decrypting page "
"at index [%ld]; rc = [%d]\n",
- __FUNCTION__, page->index, rc);
+ __func__, page->index, rc);
ClearPageUptodate(page);
goto out;
}
@@ -348,7 +348,7 @@ static int ecryptfs_prepare_write(struct file *file, struct page *page,
if (rc) {
printk(KERN_ERR "%s: Error on attempt to "
"truncate to (higher) offset [%lld];"
- " rc = [%d]\n", __FUNCTION__,
+ " rc = [%d]\n", __func__,
prev_page_end_size, rc);
goto out;
}
@@ -389,7 +389,7 @@ static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode)
kfree(file_size_virt);
if (rc)
printk(KERN_ERR "%s: Error writing file size to header; "
- "rc = [%d]\n", __FUNCTION__, rc);
+ "rc = [%d]\n", __func__, rc);
out:
return rc;
}
diff --git a/fs/ecryptfs/netlink.c b/fs/ecryptfs/netlink.c
index f638a698dc52..e0abad62b395 100644
--- a/fs/ecryptfs/netlink.c
+++ b/fs/ecryptfs/netlink.c
@@ -44,8 +44,8 @@ static struct sock *ecryptfs_nl_sock;
* upon sending the message; non-zero upon error.
*/
int ecryptfs_send_netlink(char *data, int data_len,
- struct ecryptfs_msg_ctx *msg_ctx, u16 msg_type,
- u16 msg_flags, pid_t daemon_pid)
+ struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,
+ u16 msg_flags, struct pid *daemon_pid)
{
struct sk_buff *skb;
struct nlmsghdr *nlh;
@@ -60,7 +60,7 @@ int ecryptfs_send_netlink(char *data, int data_len,
ecryptfs_printk(KERN_ERR, "Failed to allocate socket buffer\n");
goto out;
}
- nlh = NLMSG_PUT(skb, daemon_pid, msg_ctx ? msg_ctx->counter : 0,
+ nlh = NLMSG_PUT(skb, pid_nr(daemon_pid), msg_ctx ? msg_ctx->counter : 0,
msg_type, payload_len);
nlh->nlmsg_flags = msg_flags;
if (msg_ctx && payload_len) {
@@ -69,7 +69,7 @@ int ecryptfs_send_netlink(char *data, int data_len,
msg->data_len = data_len;
memcpy(msg->data, data, data_len);
}
- rc = netlink_unicast(ecryptfs_nl_sock, skb, daemon_pid, 0);
+ rc = netlink_unicast(ecryptfs_nl_sock, skb, pid_nr(daemon_pid), 0);
if (rc < 0) {
ecryptfs_printk(KERN_ERR, "Failed to send eCryptfs netlink "
"message; rc = [%d]\n", rc);
@@ -99,6 +99,7 @@ static int ecryptfs_process_nl_response(struct sk_buff *skb)
{
struct nlmsghdr *nlh = nlmsg_hdr(skb);
struct ecryptfs_message *msg = NLMSG_DATA(nlh);
+ struct pid *pid;
int rc;
if (skb->len - NLMSG_HDRLEN - sizeof(*msg) != msg->data_len) {
@@ -107,8 +108,10 @@ static int ecryptfs_process_nl_response(struct sk_buff *skb)
"incorrectly specified data length\n");
goto out;
}
- rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid,
- NETLINK_CREDS(skb)->pid, nlh->nlmsg_seq);
+ pid = find_get_pid(NETLINK_CREDS(skb)->pid);
+ rc = ecryptfs_process_response(msg, NETLINK_CREDS(skb)->uid, NULL,
+ pid, nlh->nlmsg_seq);
+ put_pid(pid);
if (rc)
printk(KERN_ERR
"Error processing response message; rc = [%d]\n", rc);
@@ -126,11 +129,13 @@ out:
*/
static int ecryptfs_process_nl_helo(struct sk_buff *skb)
{
+ struct pid *pid;
int rc;
+ pid = find_get_pid(NETLINK_CREDS(skb)->pid);
rc = ecryptfs_process_helo(ECRYPTFS_TRANSPORT_NETLINK,
- NETLINK_CREDS(skb)->uid,
- NETLINK_CREDS(skb)->pid);
+ NETLINK_CREDS(skb)->uid, NULL, pid);
+ put_pid(pid);
if (rc)
printk(KERN_WARNING "Error processing HELO; rc = [%d]\n", rc);
return rc;
@@ -147,10 +152,12 @@ static int ecryptfs_process_nl_helo(struct sk_buff *skb)
*/
static int ecryptfs_process_nl_quit(struct sk_buff *skb)
{
+ struct pid *pid;
int rc;
- rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid,
- NETLINK_CREDS(skb)->pid);
+ pid = find_get_pid(NETLINK_CREDS(skb)->pid);
+ rc = ecryptfs_process_quit(NETLINK_CREDS(skb)->uid, NULL, pid);
+ put_pid(pid);
if (rc)
printk(KERN_WARNING
"Error processing QUIT message; rc = [%d]\n", rc);
@@ -176,20 +183,20 @@ static void ecryptfs_receive_nl_message(struct sk_buff *skb)
goto free;
}
switch (nlh->nlmsg_type) {
- case ECRYPTFS_NLMSG_RESPONSE:
+ case ECRYPTFS_MSG_RESPONSE:
if (ecryptfs_process_nl_response(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"deliver netlink response to "
"requesting operation\n");
}
break;
- case ECRYPTFS_NLMSG_HELO:
+ case ECRYPTFS_MSG_HELO:
if (ecryptfs_process_nl_helo(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill HELO request\n");
}
break;
- case ECRYPTFS_NLMSG_QUIT:
+ case ECRYPTFS_MSG_QUIT:
if (ecryptfs_process_nl_quit(skb)) {
ecryptfs_printk(KERN_WARNING, "Failed to "
"fulfill QUIT request\n");
diff --git a/fs/ecryptfs/read_write.c b/fs/ecryptfs/read_write.c
index 0c4928623bbc..ebf55150be56 100644
--- a/fs/ecryptfs/read_write.c
+++ b/fs/ecryptfs/read_write.c
@@ -55,7 +55,7 @@ int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,
set_fs(fs_save);
if (octets_written < 0) {
printk(KERN_ERR "%s: octets_written = [%td]; "
- "expected [%td]\n", __FUNCTION__, octets_written, size);
+ "expected [%td]\n", __func__, octets_written, size);
rc = -EINVAL;
}
mutex_unlock(&inode_info->lower_file_mutex);
@@ -153,7 +153,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
"index [%ld] from eCryptfs inode "
- "mapping; rc = [%d]\n", __FUNCTION__,
+ "mapping; rc = [%d]\n", __func__,
ecryptfs_page_idx, rc);
goto out;
}
@@ -165,7 +165,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
"page; rc = [%d]\n",
- __FUNCTION__, rc);
+ __func__, rc);
ClearPageUptodate(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
@@ -202,7 +202,7 @@ int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,
page_cache_release(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error encrypting "
- "page; rc = [%d]\n", __FUNCTION__, rc);
+ "page; rc = [%d]\n", __func__, rc);
goto out;
}
pos += num_bytes;
@@ -254,7 +254,7 @@ int ecryptfs_read_lower(char *data, loff_t offset, size_t size,
set_fs(fs_save);
if (octets_read < 0) {
printk(KERN_ERR "%s: octets_read = [%td]; "
- "expected [%td]\n", __FUNCTION__, octets_read, size);
+ "expected [%td]\n", __func__, octets_read, size);
rc = -EINVAL;
}
mutex_unlock(&inode_info->lower_file_mutex);
@@ -327,7 +327,7 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
printk(KERN_ERR "%s: Attempt to read data past the end of the "
"file; offset = [%lld]; size = [%td]; "
"ecryptfs_file_size = [%lld]\n",
- __FUNCTION__, offset, size, ecryptfs_file_size);
+ __func__, offset, size, ecryptfs_file_size);
goto out;
}
pos = offset;
@@ -345,14 +345,14 @@ int ecryptfs_read(char *data, loff_t offset, size_t size,
rc = PTR_ERR(ecryptfs_page);
printk(KERN_ERR "%s: Error getting page at "
"index [%ld] from eCryptfs inode "
- "mapping; rc = [%d]\n", __FUNCTION__,
+ "mapping; rc = [%d]\n", __func__,
ecryptfs_page_idx, rc);
goto out;
}
rc = ecryptfs_decrypt_page(ecryptfs_page);
if (rc) {
printk(KERN_ERR "%s: Error decrypting "
- "page; rc = [%d]\n", __FUNCTION__, rc);
+ "page; rc = [%d]\n", __func__, rc);
ClearPageUptodate(ecryptfs_page);
page_cache_release(ecryptfs_page);
goto out;
diff --git a/fs/eventpoll.c b/fs/eventpoll.c
index a415f42d32cf..0d237182d721 100644
--- a/fs/eventpoll.c
+++ b/fs/eventpoll.c
@@ -257,25 +257,6 @@ static inline int ep_cmp_ffd(struct epoll_filefd *p1,
(p1->file < p2->file ? -1 : p1->fd - p2->fd));
}
-/* Special initialization for the RB tree node to detect linkage */
-static inline void ep_rb_initnode(struct rb_node *n)
-{
- rb_set_parent(n, n);
-}
-
-/* Removes a node from the RB tree and marks it for a fast is-linked check */
-static inline void ep_rb_erase(struct rb_node *n, struct rb_root *r)
-{
- rb_erase(n, r);
- rb_set_parent(n, n);
-}
-
-/* Fast check to verify that the item is linked to the main RB tree */
-static inline int ep_rb_linked(struct rb_node *n)
-{
- return rb_parent(n) != n;
-}
-
/* Tells us if the item is currently linked */
static inline int ep_is_linked(struct list_head *p)
{
@@ -283,13 +264,13 @@ static inline int ep_is_linked(struct list_head *p)
}
/* Get the "struct epitem" from a wait queue pointer */
-static inline struct epitem * ep_item_from_wait(wait_queue_t *p)
+static inline struct epitem *ep_item_from_wait(wait_queue_t *p)
{
return container_of(p, struct eppoll_entry, wait)->base;
}
/* Get the "struct epitem" from an epoll queue wrapper */
-static inline struct epitem * ep_item_from_epqueue(poll_table *p)
+static inline struct epitem *ep_item_from_epqueue(poll_table *p)
{
return container_of(p, struct ep_pqueue, pt)->epi;
}
@@ -411,8 +392,7 @@ static int ep_remove(struct eventpoll *ep, struct epitem *epi)
list_del_init(&epi->fllink);
spin_unlock(&file->f_ep_lock);
- if (ep_rb_linked(&epi->rbn))
- ep_rb_erase(&epi->rbn, &ep->rbr);
+ rb_erase(&epi->rbn, &ep->rbr);
spin_lock_irqsave(&ep->lock, flags);
if (ep_is_linked(&epi->rdllink))
@@ -728,7 +708,6 @@ static int ep_insert(struct eventpoll *ep, struct epoll_event *event,
goto error_return;
/* Item initialization follow here ... */
- ep_rb_initnode(&epi->rbn);
INIT_LIST_HEAD(&epi->rdllink);
INIT_LIST_HEAD(&epi->fllink);
INIT_LIST_HEAD(&epi->pwqlist);
diff --git a/fs/exec.c b/fs/exec.c
index b152029f18f6..a13883903ee9 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -735,6 +735,7 @@ static int exec_mmap(struct mm_struct *mm)
tsk->active_mm = mm;
activate_mm(active_mm, mm);
task_unlock(tsk);
+ mm_update_next_owner(mm);
arch_pick_mmap_layout(mm);
if (old_mm) {
up_read(&old_mm->mmap_sem);
@@ -963,6 +964,8 @@ int flush_old_exec(struct linux_binprm * bprm)
if (retval)
goto out;
+ set_mm_exe_file(bprm->mm, bprm->file);
+
/*
* Release all of the old mmap stuff
*/
@@ -1268,7 +1271,6 @@ int do_execve(char * filename,
{
struct linux_binprm *bprm;
struct file *file;
- unsigned long env_p;
struct files_struct *displaced;
int retval;
@@ -1321,11 +1323,9 @@ int do_execve(char * filename,
if (retval < 0)
goto out;
- env_p = bprm->p;
retval = copy_strings(bprm->argc, argv, bprm);
if (retval < 0)
goto out;
- bprm->argv_len = env_p - bprm->p;
retval = search_binary_handler(bprm,regs);
if (retval >= 0) {
diff --git a/fs/ext4/mballoc.c b/fs/ext4/mballoc.c
index ef97f19c2f9d..9d57695de746 100644
--- a/fs/ext4/mballoc.c
+++ b/fs/ext4/mballoc.c
@@ -2449,17 +2449,10 @@ static void ext4_mb_history_init(struct super_block *sb)
int i;
if (sbi->s_mb_proc != NULL) {
- struct proc_dir_entry *p;
- p = create_proc_entry("mb_history", S_IRUGO, sbi->s_mb_proc);
- if (p) {
- p->proc_fops = &ext4_mb_seq_history_fops;
- p->data = sb;
- }
- p = create_proc_entry("mb_groups", S_IRUGO, sbi->s_mb_proc);
- if (p) {
- p->proc_fops = &ext4_mb_seq_groups_fops;
- p->data = sb;
- }
+ proc_create_data("mb_history", S_IRUGO, sbi->s_mb_proc,
+ &ext4_mb_seq_history_fops, sb);
+ proc_create_data("mb_groups", S_IRUGO, sbi->s_mb_proc,
+ &ext4_mb_seq_groups_fops, sb);
}
sbi->s_mb_history_max = 1000;
@@ -2867,7 +2860,6 @@ static void ext4_mb_free_committed_blocks(struct super_block *sb)
mb_debug("freed %u blocks in %u structures\n", count, count2);
}
-#define EXT4_ROOT "ext4"
#define EXT4_MB_STATS_NAME "stats"
#define EXT4_MB_MAX_TO_SCAN_NAME "max_to_scan"
#define EXT4_MB_MIN_TO_SCAN_NAME "min_to_scan"
@@ -3007,9 +2999,9 @@ int __init init_ext4_mballoc(void)
return -ENOMEM;
}
#ifdef CONFIG_PROC_FS
- proc_root_ext4 = proc_mkdir(EXT4_ROOT, proc_root_fs);
+ proc_root_ext4 = proc_mkdir("fs/ext4", NULL);
if (proc_root_ext4 == NULL)
- printk(KERN_ERR "EXT4-fs: Unable to create %s\n", EXT4_ROOT);
+ printk(KERN_ERR "EXT4-fs: Unable to create fs/ext4\n");
#endif
return 0;
}
@@ -3020,7 +3012,7 @@ void exit_ext4_mballoc(void)
kmem_cache_destroy(ext4_pspace_cachep);
kmem_cache_destroy(ext4_ac_cachep);
#ifdef CONFIG_PROC_FS
- remove_proc_entry(EXT4_ROOT, proc_root_fs);
+ remove_proc_entry("fs/ext4", NULL);
#endif
}
diff --git a/fs/fat/inode.c b/fs/fat/inode.c
index 5f522a55b596..4e0a3dd9d677 100644
--- a/fs/fat/inode.c
+++ b/fs/fat/inode.c
@@ -1222,8 +1222,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
brelse(bh);
goto out_invalid;
}
- logical_sector_size =
- le16_to_cpu(get_unaligned((__le16 *)&b->sector_size));
+ logical_sector_size = get_unaligned_le16(&b->sector_size);
if (!is_power_of_2(logical_sector_size)
|| (logical_sector_size < 512)
|| (logical_sector_size > 4096)) {
@@ -1322,8 +1321,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
sbi->dir_per_block_bits = ffs(sbi->dir_per_block) - 1;
sbi->dir_start = sbi->fat_start + sbi->fats * sbi->fat_length;
- sbi->dir_entries =
- le16_to_cpu(get_unaligned((__le16 *)&b->dir_entries));
+ sbi->dir_entries = get_unaligned_le16(&b->dir_entries);
if (sbi->dir_entries & (sbi->dir_per_block - 1)) {
if (!silent)
printk(KERN_ERR "FAT: bogus directroy-entries per block"
@@ -1335,7 +1333,7 @@ int fat_fill_super(struct super_block *sb, void *data, int silent,
rootdir_sectors = sbi->dir_entries
* sizeof(struct msdos_dir_entry) / sb->s_blocksize;
sbi->data_start = sbi->dir_start + rootdir_sectors;
- total_sectors = le16_to_cpu(get_unaligned((__le16 *)&b->sectors));
+ total_sectors = get_unaligned_le16(&b->sectors);
if (total_sectors == 0)
total_sectors = le32_to_cpu(b->total_sect);
diff --git a/fs/freevxfs/vxfs_extern.h b/fs/freevxfs/vxfs_extern.h
index 2b46064f66b2..50ab5eecb99b 100644
--- a/fs/freevxfs/vxfs_extern.h
+++ b/fs/freevxfs/vxfs_extern.h
@@ -50,7 +50,11 @@ extern daddr_t vxfs_bmap1(struct inode *, long);
/* vxfs_fshead.c */
extern int vxfs_read_fshead(struct super_block *);
+/* vxfs_immed.c */
+extern const struct inode_operations vxfs_immed_symlink_iops;
+
/* vxfs_inode.c */
+extern const struct address_space_operations vxfs_immed_aops;
extern struct kmem_cache *vxfs_inode_cachep;
extern void vxfs_dumpi(struct vxfs_inode_info *, ino_t);
extern struct inode * vxfs_get_fake_inode(struct super_block *,
@@ -69,6 +73,7 @@ extern const struct file_operations vxfs_dir_operations;
extern int vxfs_read_olt(struct super_block *, u_long);
/* vxfs_subr.c */
+extern const struct address_space_operations vxfs_aops;
extern struct page * vxfs_get_page(struct address_space *, u_long);
extern void vxfs_put_page(struct page *);
extern struct buffer_head * vxfs_bread(struct inode *, int);
diff --git a/fs/freevxfs/vxfs_immed.c b/fs/freevxfs/vxfs_immed.c
index 8a5959a61ba9..c36aeaf92e41 100644
--- a/fs/freevxfs/vxfs_immed.c
+++ b/fs/freevxfs/vxfs_immed.c
@@ -35,6 +35,7 @@
#include <linux/namei.h>
#include "vxfs.h"
+#include "vxfs_extern.h"
#include "vxfs_inode.h"
diff --git a/fs/freevxfs/vxfs_inode.c b/fs/freevxfs/vxfs_inode.c
index ad88d2364bc2..9f3f2ceb73f0 100644
--- a/fs/freevxfs/vxfs_inode.c
+++ b/fs/freevxfs/vxfs_inode.c
@@ -41,11 +41,6 @@
#include "vxfs_extern.h"
-extern const struct address_space_operations vxfs_aops;
-extern const struct address_space_operations vxfs_immed_aops;
-
-extern const struct inode_operations vxfs_immed_symlink_iops;
-
struct kmem_cache *vxfs_inode_cachep;
diff --git a/fs/fs-writeback.c b/fs/fs-writeback.c
index 06557679ca41..ae45f77765c0 100644
--- a/fs/fs-writeback.c
+++ b/fs/fs-writeback.c
@@ -25,6 +25,45 @@
#include <linux/buffer_head.h>
#include "internal.h"
+
+/**
+ * writeback_acquire - attempt to get exclusive writeback access to a device
+ * @bdi: the device's backing_dev_info structure
+ *
+ * It is a waste of resources to have more than one pdflush thread blocked on
+ * a single request queue. Exclusion at the request_queue level is obtained
+ * via a flag in the request_queue's backing_dev_info.state.
+ *
+ * Non-request_queue-backed address_spaces will share default_backing_dev_info,
+ * unless they implement their own. Which is somewhat inefficient, as this
+ * may prevent concurrent writeback against multiple devices.
+ */
+static int writeback_acquire(struct backing_dev_info *bdi)
+{
+ return !test_and_set_bit(BDI_pdflush, &bdi->state);
+}
+
+/**
+ * writeback_in_progress - determine whether there is writeback in progress
+ * @bdi: the device's backing_dev_info structure.
+ *
+ * Determine whether there is writeback in progress against a backing device.
+ */
+int writeback_in_progress(struct backing_dev_info *bdi)
+{
+ return test_bit(BDI_pdflush, &bdi->state);
+}
+
+/**
+ * writeback_release - relinquish exclusive writeback access against a device.
+ * @bdi: the device's backing_dev_info structure
+ */
+static void writeback_release(struct backing_dev_info *bdi)
+{
+ BUG_ON(!writeback_in_progress(bdi));
+ clear_bit(BDI_pdflush, &bdi->state);
+}
+
/**
* __mark_inode_dirty - internal function
* @inode: inode to mark
@@ -747,43 +786,4 @@ int generic_osync_inode(struct inode *inode, struct address_space *mapping, int
return err;
}
-
EXPORT_SYMBOL(generic_osync_inode);
-
-/**
- * writeback_acquire - attempt to get exclusive writeback access to a device
- * @bdi: the device's backing_dev_info structure
- *
- * It is a waste of resources to have more than one pdflush thread blocked on
- * a single request queue. Exclusion at the request_queue level is obtained
- * via a flag in the request_queue's backing_dev_info.state.
- *
- * Non-request_queue-backed address_spaces will share default_backing_dev_info,
- * unless they implement their own. Which is somewhat inefficient, as this
- * may prevent concurrent writeback against multiple devices.
- */
-int writeback_acquire(struct backing_dev_info *bdi)
-{
- return !test_and_set_bit(BDI_pdflush, &bdi->state);
-}
-
-/**
- * writeback_in_progress - determine whether there is writeback in progress
- * @bdi: the device's backing_dev_info structure.
- *
- * Determine whether there is writeback in progress against a backing device.
- */
-int writeback_in_progress(struct backing_dev_info *bdi)
-{
- return test_bit(BDI_pdflush, &bdi->state);
-}
-
-/**
- * writeback_release - relinquish exclusive writeback access against a device.
- * @bdi: the device's backing_dev_info structure
- */
-void writeback_release(struct backing_dev_info *bdi)
-{
- BUG_ON(!writeback_in_progress(bdi));
- clear_bit(BDI_pdflush, &bdi->state);
-}
diff --git a/fs/hfs/super.c b/fs/hfs/super.c
index 32de44ed0021..8cf67974adf6 100644
--- a/fs/hfs/super.c
+++ b/fs/hfs/super.c
@@ -297,7 +297,8 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
return 0;
}
p = match_strdup(&args[0]);
- hsb->nls_disk = load_nls(p);
+ if (p)
+ hsb->nls_disk = load_nls(p);
if (!hsb->nls_disk) {
printk(KERN_ERR "hfs: unable to load codepage \"%s\"\n", p);
kfree(p);
@@ -311,7 +312,8 @@ static int parse_options(char *options, struct hfs_sb_info *hsb)
return 0;
}
p = match_strdup(&args[0]);
- hsb->nls_io = load_nls(p);
+ if (p)
+ hsb->nls_io = load_nls(p);
if (!hsb->nls_io) {
printk(KERN_ERR "hfs: unable to load iocharset \"%s\"\n", p);
kfree(p);
diff --git a/fs/hfsplus/hfsplus_fs.h b/fs/hfsplus/hfsplus_fs.h
index d72d0a8b25aa..9e59537b43d5 100644
--- a/fs/hfsplus/hfsplus_fs.h
+++ b/fs/hfsplus/hfsplus_fs.h
@@ -311,6 +311,10 @@ int hfsplus_delete_cat(u32, struct inode *, struct qstr *);
int hfsplus_rename_cat(u32, struct inode *, struct qstr *,
struct inode *, struct qstr *);
+/* dir.c */
+extern const struct inode_operations hfsplus_dir_inode_operations;
+extern const struct file_operations hfsplus_dir_operations;
+
/* extents.c */
int hfsplus_ext_cmp_key(const hfsplus_btree_key *, const hfsplus_btree_key *);
void hfsplus_ext_write_extent(struct inode *);
diff --git a/fs/hfsplus/inode.c b/fs/hfsplus/inode.c
index 37744cf3706a..d53b2af91c25 100644
--- a/fs/hfsplus/inode.c
+++ b/fs/hfsplus/inode.c
@@ -278,9 +278,6 @@ static int hfsplus_file_release(struct inode *inode, struct file *file)
return 0;
}
-extern const struct inode_operations hfsplus_dir_inode_operations;
-extern struct file_operations hfsplus_dir_operations;
-
static const struct inode_operations hfsplus_file_inode_operations = {
.lookup = hfsplus_file_lookup,
.truncate = hfsplus_file_truncate,
diff --git a/fs/hfsplus/options.c b/fs/hfsplus/options.c
index dc64fac00831..9997cbf8beb5 100644
--- a/fs/hfsplus/options.c
+++ b/fs/hfsplus/options.c
@@ -132,7 +132,8 @@ int hfsplus_parse_options(char *input, struct hfsplus_sb_info *sbi)
return 0;
}
p = match_strdup(&args[0]);
- sbi->nls = load_nls(p);
+ if (p)
+ sbi->nls = load_nls(p);
if (!sbi->nls) {
printk(KERN_ERR "hfs: unable to load nls mapping \"%s\"\n", p);
kfree(p);
diff --git a/fs/hfsplus/wrapper.c b/fs/hfsplus/wrapper.c
index 72cab78f0509..175d08eacc86 100644
--- a/fs/hfsplus/wrapper.c
+++ b/fs/hfsplus/wrapper.c
@@ -47,7 +47,7 @@ static int hfsplus_read_mdb(void *bufptr, struct hfsplus_wd *wd)
return 0;
wd->ablk_start = be16_to_cpu(*(__be16 *)(bufptr + HFSP_WRAPOFF_ABLKSTART));
- extent = be32_to_cpu(get_unaligned((__be32 *)(bufptr + HFSP_WRAPOFF_EMBEDEXT)));
+ extent = get_unaligned_be32(bufptr + HFSP_WRAPOFF_EMBEDEXT);
wd->embed_start = (extent >> 16) & 0xFFFF;
wd->embed_count = extent & 0xFFFF;
diff --git a/fs/inode.c b/fs/inode.c
index 27ee1af50d02..bf6478130424 100644
--- a/fs/inode.c
+++ b/fs/inode.c
@@ -495,8 +495,7 @@ static struct inode * find_inode(struct super_block * sb, struct hlist_head *hea
struct inode * inode = NULL;
repeat:
- hlist_for_each (node, head) {
- inode = hlist_entry(node, struct inode, i_hash);
+ hlist_for_each_entry(inode, node, head, i_hash) {
if (inode->i_sb != sb)
continue;
if (!test(inode, data))
@@ -520,8 +519,7 @@ static struct inode * find_inode_fast(struct super_block * sb, struct hlist_head
struct inode * inode = NULL;
repeat:
- hlist_for_each (node, head) {
- inode = hlist_entry(node, struct inode, i_hash);
+ hlist_for_each_entry(inode, node, head, i_hash) {
if (inode->i_ino != ino)
continue;
if (inode->i_sb != sb)
diff --git a/fs/inotify_user.c b/fs/inotify_user.c
index 7b94a1e3c015..6676c06bb7c1 100644
--- a/fs/inotify_user.c
+++ b/fs/inotify_user.c
@@ -598,7 +598,7 @@ asmlinkage long sys_inotify_init(void)
}
ih = inotify_init(&inotify_user_ops);
- if (unlikely(IS_ERR(ih))) {
+ if (IS_ERR(ih)) {
ret = PTR_ERR(ih);
goto out_free_dev;
}
diff --git a/fs/ioctl.c b/fs/ioctl.c
index f32fbde2175e..7db32b3382d3 100644
--- a/fs/ioctl.c
+++ b/fs/ioctl.c
@@ -28,8 +28,8 @@
*
* Returns 0 on success, -errno on error.
*/
-long vfs_ioctl(struct file *filp, unsigned int cmd,
- unsigned long arg)
+static long vfs_ioctl(struct file *filp, unsigned int cmd,
+ unsigned long arg)
{
int error = -ENOTTY;
diff --git a/fs/isofs/isofs.h b/fs/isofs/isofs.h
index d1bdf8adb351..ccbf72faf27a 100644
--- a/fs/isofs/isofs.h
+++ b/fs/isofs/isofs.h
@@ -78,29 +78,29 @@ static inline int isonum_712(char *p)
}
static inline unsigned int isonum_721(char *p)
{
- return le16_to_cpu(get_unaligned((__le16 *)p));
+ return get_unaligned_le16(p);
}
static inline unsigned int isonum_722(char *p)
{
- return be16_to_cpu(get_unaligned((__le16 *)p));
+ return get_unaligned_be16(p);
}
static inline unsigned int isonum_723(char *p)
{
/* Ignore bigendian datum due to broken mastering programs */
- return le16_to_cpu(get_unaligned((__le16 *)p));
+ return get_unaligned_le16(p);
}
static inline unsigned int isonum_731(char *p)
{
- return le32_to_cpu(get_unaligned((__le32 *)p));
+ return get_unaligned_le32(p);
}
static inline unsigned int isonum_732(char *p)
{
- return be32_to_cpu(get_unaligned((__le32 *)p));
+ return get_unaligned_be32(p);
}
static inline unsigned int isonum_733(char *p)
{
/* Ignore bigendian datum due to broken mastering programs */
- return le32_to_cpu(get_unaligned((__le32 *)p));
+ return get_unaligned_le32(p);
}
extern int iso_date(char *, int);
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 954cff001df6..eb7eb6c27bcb 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -904,19 +904,10 @@ static void jbd2_stats_proc_init(journal_t *journal)
snprintf(name, sizeof(name) - 1, "%s", bdevname(journal->j_dev, name));
journal->j_proc_entry = proc_mkdir(name, proc_jbd2_stats);
if (journal->j_proc_entry) {
- struct proc_dir_entry *p;
- p = create_proc_entry("history", S_IRUGO,
- journal->j_proc_entry);
- if (p) {
- p->proc_fops = &jbd2_seq_history_fops;
- p->data = journal;
- p = create_proc_entry("info", S_IRUGO,
- journal->j_proc_entry);
- if (p) {
- p->proc_fops = &jbd2_seq_info_fops;
- p->data = journal;
- }
- }
+ proc_create_data("history", S_IRUGO, journal->j_proc_entry,
+ &jbd2_seq_history_fops, journal);
+ proc_create_data("info", S_IRUGO, journal->j_proc_entry,
+ &jbd2_seq_info_fops, journal);
}
}
diff --git a/fs/jfs/jfs_debug.c b/fs/jfs/jfs_debug.c
index 887f5759e536..bf6ab19b86ee 100644
--- a/fs/jfs/jfs_debug.c
+++ b/fs/jfs/jfs_debug.c
@@ -89,7 +89,7 @@ void jfs_proc_init(void)
{
int i;
- if (!(base = proc_mkdir("jfs", proc_root_fs)))
+ if (!(base = proc_mkdir("fs/jfs", NULL)))
return;
base->owner = THIS_MODULE;
@@ -109,7 +109,7 @@ void jfs_proc_clean(void)
if (base) {
for (i = 0; i < NPROCENT; i++)
remove_proc_entry(Entries[i].name, base);
- remove_proc_entry("jfs", proc_root_fs);
+ remove_proc_entry("fs/jfs", NULL);
}
}
diff --git a/fs/namei.c b/fs/namei.c
index e179f71bfcb0..32fd9655485b 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -30,6 +30,7 @@
#include <linux/capability.h>
#include <linux/file.h>
#include <linux/fcntl.h>
+#include <linux/device_cgroup.h>
#include <asm/namei.h>
#include <asm/uaccess.h>
@@ -281,6 +282,10 @@ int permission(struct inode *inode, int mask, struct nameidata *nd)
if (retval)
return retval;
+ retval = devcgroup_inode_permission(inode, mask);
+ if (retval)
+ return retval;
+
return security_inode_permission(inode, mask, nd);
}
@@ -2028,6 +2033,10 @@ int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
if (!dir->i_op || !dir->i_op->mknod)
return -EPERM;
+ error = devcgroup_inode_mknod(mode, dev);
+ if (error)
+ return error;
+
error = security_inode_mknod(dir, dentry, mode, dev);
if (error)
return error;
diff --git a/fs/namespace.c b/fs/namespace.c
index fe376805cf5f..061e5edb4d27 100644
--- a/fs/namespace.c
+++ b/fs/namespace.c
@@ -1176,17 +1176,6 @@ static int mount_is_safe(struct nameidata *nd)
#endif
}
-static int lives_below_in_same_fs(struct dentry *d, struct dentry *dentry)
-{
- while (1) {
- if (d == dentry)
- return 1;
- if (d == NULL || d == d->d_parent)
- return 0;
- d = d->d_parent;
- }
-}
-
struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
int flag)
{
@@ -1203,7 +1192,7 @@ struct vfsmount *copy_tree(struct vfsmount *mnt, struct dentry *dentry,
p = mnt;
list_for_each_entry(r, &mnt->mnt_mounts, mnt_child) {
- if (!lives_below_in_same_fs(r->mnt_mountpoint, dentry))
+ if (!is_subdir(r->mnt_mountpoint, dentry))
continue;
for (s = r; s; s = next_mnt(s, r)) {
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
index df6d60bdfcd3..97645f112114 100644
--- a/fs/ncpfs/ncplib_kernel.c
+++ b/fs/ncpfs/ncplib_kernel.c
@@ -102,48 +102,47 @@ static inline void ncp_init_request_s(struct ncp_server *server, int subfunction
}
static inline char *
- ncp_reply_data(struct ncp_server *server, int offset)
+ncp_reply_data(struct ncp_server *server, int offset)
{
return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
}
-static inline __u8 BVAL(void* data)
+static inline u8 BVAL(void *data)
{
- return get_unaligned((__u8*)data);
+ return *(u8 *)data;
}
-static __u8
- ncp_reply_byte(struct ncp_server *server, int offset)
+static u8 ncp_reply_byte(struct ncp_server *server, int offset)
{
- return get_unaligned((__u8 *) ncp_reply_data(server, offset));
+ return *(u8 *)ncp_reply_data(server, offset);
}
-static inline __u16 WVAL_LH(void* data)
+static inline u16 WVAL_LH(void *data)
{
- return le16_to_cpu(get_unaligned((__le16*)data));
+ return get_unaligned_le16(data);
}
-static __u16
- ncp_reply_le16(struct ncp_server *server, int offset)
+static u16
+ncp_reply_le16(struct ncp_server *server, int offset)
{
- return le16_to_cpu(get_unaligned((__le16 *) ncp_reply_data(server, offset)));
+ return get_unaligned_le16(ncp_reply_data(server, offset));
}
-static __u16
- ncp_reply_be16(struct ncp_server *server, int offset)
+static u16
+ncp_reply_be16(struct ncp_server *server, int offset)
{
- return be16_to_cpu(get_unaligned((__be16 *) ncp_reply_data(server, offset)));
+ return get_unaligned_be16(ncp_reply_data(server, offset));
}
-static inline __u32 DVAL_LH(void* data)
+static inline u32 DVAL_LH(void *data)
{
- return le32_to_cpu(get_unaligned((__le32*)data));
+ return get_unaligned_le32(data);
}
static __le32
- ncp_reply_dword(struct ncp_server *server, int offset)
+ncp_reply_dword(struct ncp_server *server, int offset)
{
- return get_unaligned((__le32 *) ncp_reply_data(server, offset));
+ return get_unaligned((__le32 *)ncp_reply_data(server, offset));
}
static inline __u32 ncp_reply_dword_lh(struct ncp_server* server, int offset) {
@@ -1006,8 +1005,8 @@ ncp_read_bounce(struct ncp_server *server, const char *file_id,
result = ncp_request2(server, 72, bounce, bufsize);
ncp_unlock_server(server);
if (!result) {
- int len = be16_to_cpu(get_unaligned((__be16*)((char*)bounce +
- sizeof(struct ncp_reply_header))));
+ int len = get_unaligned_be16((char *)bounce +
+ sizeof(struct ncp_reply_header));
result = -EIO;
if (len <= to_read) {
char* source;
diff --git a/fs/nfs/client.c b/fs/nfs/client.c
index f2f3b284e6dd..89ac5bb0401c 100644
--- a/fs/nfs/client.c
+++ b/fs/nfs/client.c
@@ -1321,6 +1321,7 @@ static const struct file_operations nfs_server_list_fops = {
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
static int nfs_volume_list_open(struct inode *inode, struct file *file);
@@ -1341,6 +1342,7 @@ static const struct file_operations nfs_volume_list_fops = {
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
/*
@@ -1500,33 +1502,29 @@ int __init nfs_fs_proc_init(void)
{
struct proc_dir_entry *p;
- proc_fs_nfs = proc_mkdir("nfsfs", proc_root_fs);
+ proc_fs_nfs = proc_mkdir("fs/nfsfs", NULL);
if (!proc_fs_nfs)
goto error_0;
proc_fs_nfs->owner = THIS_MODULE;
/* a file of servers with which we're dealing */
- p = create_proc_entry("servers", S_IFREG|S_IRUGO, proc_fs_nfs);
+ p = proc_create("servers", S_IFREG|S_IRUGO,
+ proc_fs_nfs, &nfs_server_list_fops);
if (!p)
goto error_1;
- p->proc_fops = &nfs_server_list_fops;
- p->owner = THIS_MODULE;
-
/* a file of volumes that we have mounted */
- p = create_proc_entry("volumes", S_IFREG|S_IRUGO, proc_fs_nfs);
+ p = proc_create("volumes", S_IFREG|S_IRUGO,
+ proc_fs_nfs, &nfs_volume_list_fops);
if (!p)
goto error_2;
-
- p->proc_fops = &nfs_volume_list_fops;
- p->owner = THIS_MODULE;
return 0;
error_2:
remove_proc_entry("servers", proc_fs_nfs);
error_1:
- remove_proc_entry("nfsfs", proc_root_fs);
+ remove_proc_entry("fs/nfsfs", NULL);
error_0:
return -ENOMEM;
}
@@ -1538,7 +1536,7 @@ void nfs_fs_proc_exit(void)
{
remove_proc_entry("volumes", proc_fs_nfs);
remove_proc_entry("servers", proc_fs_nfs);
- remove_proc_entry("nfsfs", proc_root_fs);
+ remove_proc_entry("fs/nfsfs", NULL);
}
#endif /* CONFIG_PROC_FS */
diff --git a/fs/nfsd/nfsctl.c b/fs/nfsd/nfsctl.c
index 42f3820ee8f5..5ac00c4fee91 100644
--- a/fs/nfsd/nfsctl.c
+++ b/fs/nfsd/nfsctl.c
@@ -169,6 +169,7 @@ static const struct file_operations exports_operations = {
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
/*----------------------------------------------------------------------------*/
@@ -801,10 +802,9 @@ static int create_proc_exports_entry(void)
entry = proc_mkdir("fs/nfs", NULL);
if (!entry)
return -ENOMEM;
- entry = create_proc_entry("fs/nfs/exports", 0, NULL);
+ entry = proc_create("exports", 0, entry, &exports_operations);
if (!entry)
return -ENOMEM;
- entry->proc_fops = &exports_operations;
return 0;
}
#else /* CONFIG_PROC_FS */
diff --git a/fs/ntfs/mft.c b/fs/ntfs/mft.c
index 2ad5c8b104b9..790defb847e7 100644
--- a/fs/ntfs/mft.c
+++ b/fs/ntfs/mft.c
@@ -1191,7 +1191,7 @@ static int ntfs_mft_bitmap_find_and_alloc_free_rec_nolock(ntfs_volume *vol,
if (size) {
page = ntfs_map_page(mftbmp_mapping,
ofs >> PAGE_CACHE_SHIFT);
- if (unlikely(IS_ERR(page))) {
+ if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to read mft "
"bitmap, aborting.");
return PTR_ERR(page);
@@ -2118,7 +2118,7 @@ static int ntfs_mft_record_format(const ntfs_volume *vol, const s64 mft_no)
}
/* Read, map, and pin the page containing the mft record. */
page = ntfs_map_page(mft_vi->i_mapping, index);
- if (unlikely(IS_ERR(page))) {
+ if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to map page containing mft record "
"to format 0x%llx.", (long long)mft_no);
return PTR_ERR(page);
@@ -2519,7 +2519,7 @@ mft_rec_already_initialized:
ofs = (bit << vol->mft_record_size_bits) & ~PAGE_CACHE_MASK;
/* Read, map, and pin the page containing the mft record. */
page = ntfs_map_page(vol->mft_ino->i_mapping, index);
- if (unlikely(IS_ERR(page))) {
+ if (IS_ERR(page)) {
ntfs_error(vol->sb, "Failed to map page containing allocated "
"mft record 0x%llx.", (long long)bit);
err = PTR_ERR(page);
diff --git a/fs/proc/base.c b/fs/proc/base.c
index c5e412a00b17..fcf02f2deeba 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -195,12 +195,32 @@ static int proc_root_link(struct inode *inode, struct path *path)
return result;
}
-#define MAY_PTRACE(task) \
- (task == current || \
- (task->parent == current && \
- (task->ptrace & PT_PTRACED) && \
- (task_is_stopped_or_traced(task)) && \
- security_ptrace(current,task) == 0))
+/*
+ * Return zero if current may access user memory in @task, -error if not.
+ */
+static int check_mem_permission(struct task_struct *task)
+{
+ /*
+ * A task can always look at itself, in case it chooses
+ * to use system calls instead of load instructions.
+ */
+ if (task == current)
+ return 0;
+
+ /*
+ * If current is actively ptrace'ing, and would also be
+ * permitted to freshly attach with ptrace now, permit it.
+ */
+ if (task->parent == current && (task->ptrace & PT_PTRACED) &&
+ task_is_stopped_or_traced(task) &&
+ ptrace_may_attach(task))
+ return 0;
+
+ /*
+ * Noone else is allowed.
+ */
+ return -EPERM;
+}
struct mm_struct *mm_for_maps(struct task_struct *task)
{
@@ -722,7 +742,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
if (!task)
goto out_no_task;
- if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+ if (check_mem_permission(task))
goto out;
ret = -ENOMEM;
@@ -748,7 +768,7 @@ static ssize_t mem_read(struct file * file, char __user * buf,
this_len = (count > PAGE_SIZE) ? PAGE_SIZE : count;
retval = access_process_vm(task, src, page, this_len, 0);
- if (!retval || !MAY_PTRACE(task) || !ptrace_may_attach(task)) {
+ if (!retval || check_mem_permission(task)) {
if (!ret)
ret = -EIO;
break;
@@ -792,7 +812,7 @@ static ssize_t mem_write(struct file * file, const char __user *buf,
if (!task)
goto out_no_task;
- if (!MAY_PTRACE(task) || !ptrace_may_attach(task))
+ if (check_mem_permission(task))
goto out;
copied = -ENOMEM;
@@ -1181,6 +1201,81 @@ static const struct file_operations proc_pid_sched_operations = {
#endif
+/*
+ * We added or removed a vma mapping the executable. The vmas are only mapped
+ * during exec and are not mapped with the mmap system call.
+ * Callers must hold down_write() on the mm's mmap_sem for these
+ */
+void added_exe_file_vma(struct mm_struct *mm)
+{
+ mm->num_exe_file_vmas++;
+}
+
+void removed_exe_file_vma(struct mm_struct *mm)
+{
+ mm->num_exe_file_vmas--;
+ if ((mm->num_exe_file_vmas == 0) && mm->exe_file){
+ fput(mm->exe_file);
+ mm->exe_file = NULL;
+ }
+
+}
+
+void set_mm_exe_file(struct mm_struct *mm, struct file *new_exe_file)
+{
+ if (new_exe_file)
+ get_file(new_exe_file);
+ if (mm->exe_file)
+ fput(mm->exe_file);
+ mm->exe_file = new_exe_file;
+ mm->num_exe_file_vmas = 0;
+}
+
+struct file *get_mm_exe_file(struct mm_struct *mm)
+{
+ struct file *exe_file;
+
+ /* We need mmap_sem to protect against races with removal of
+ * VM_EXECUTABLE vmas */
+ down_read(&mm->mmap_sem);
+ exe_file = mm->exe_file;
+ if (exe_file)
+ get_file(exe_file);
+ up_read(&mm->mmap_sem);
+ return exe_file;
+}
+
+void dup_mm_exe_file(struct mm_struct *oldmm, struct mm_struct *newmm)
+{
+ /* It's safe to write the exe_file pointer without exe_file_lock because
+ * this is called during fork when the task is not yet in /proc */
+ newmm->exe_file = get_mm_exe_file(oldmm);
+}
+
+static int proc_exe_link(struct inode *inode, struct path *exe_path)
+{
+ struct task_struct *task;
+ struct mm_struct *mm;
+ struct file *exe_file;
+
+ task = get_proc_task(inode);
+ if (!task)
+ return -ENOENT;
+ mm = get_task_mm(task);
+ put_task_struct(task);
+ if (!mm)
+ return -ENOENT;
+ exe_file = get_mm_exe_file(mm);
+ mmput(mm);
+ if (exe_file) {
+ *exe_path = exe_file->f_path;
+ path_get(&exe_file->f_path);
+ fput(exe_file);
+ return 0;
+ } else
+ return -ENOENT;
+}
+
static void *proc_pid_follow_link(struct dentry *dentry, struct nameidata *nd)
{
struct inode *inode = dentry->d_inode;
diff --git a/fs/proc/generic.c b/fs/proc/generic.c
index a36ad3c75cf4..9d53b39a9cf8 100644
--- a/fs/proc/generic.c
+++ b/fs/proc/generic.c
@@ -69,12 +69,7 @@ proc_file_read(struct file *file, char __user *buf, size_t nbytes,
count = min_t(size_t, PROC_BLOCK_SIZE, nbytes);
start = NULL;
- if (dp->get_info) {
- /* Handle old net routines */
- n = dp->get_info(page, &start, *ppos, count);
- if (n < count)
- eof = 1;
- } else if (dp->read_proc) {
+ if (dp->read_proc) {
/*
* How to be a proc read function
* ------------------------------
@@ -277,8 +272,11 @@ static int xlate_proc_name(const char *name,
int len;
int rtn = 0;
+ de = *ret;
+ if (!de)
+ de = &proc_root;
+
spin_lock(&proc_subdir_lock);
- de = &proc_root;
while (1) {
next = strchr(cp, '/');
if (!next)
@@ -385,20 +383,18 @@ struct dentry *proc_lookup_de(struct proc_dir_entry *de, struct inode *dir,
lock_kernel();
spin_lock(&proc_subdir_lock);
- if (de) {
- for (de = de->subdir; de ; de = de->next) {
- if (de->namelen != dentry->d_name.len)
- continue;
- if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
- unsigned int ino;
+ for (de = de->subdir; de ; de = de->next) {
+ if (de->namelen != dentry->d_name.len)
+ continue;
+ if (!memcmp(dentry->d_name.name, de->name, de->namelen)) {
+ unsigned int ino;
- ino = de->low_ino;
- de_get(de);
- spin_unlock(&proc_subdir_lock);
- error = -EINVAL;
- inode = proc_get_inode(dir->i_sb, ino, de);
- goto out_unlock;
- }
+ ino = de->low_ino;
+ de_get(de);
+ spin_unlock(&proc_subdir_lock);
+ error = -EINVAL;
+ inode = proc_get_inode(dir->i_sb, ino, de);
+ goto out_unlock;
}
}
spin_unlock(&proc_subdir_lock);
@@ -410,7 +406,8 @@ out_unlock:
d_add(dentry, inode);
return NULL;
}
- de_put(de);
+ if (de)
+ de_put(de);
return ERR_PTR(error);
}
@@ -440,10 +437,6 @@ int proc_readdir_de(struct proc_dir_entry *de, struct file *filp, void *dirent,
lock_kernel();
ino = inode->i_ino;
- if (!de) {
- ret = -EINVAL;
- goto out;
- }
i = filp->f_pos;
switch (i) {
case 0:
@@ -582,7 +575,7 @@ static struct proc_dir_entry *__proc_create(struct proc_dir_entry **parent,
/* make sure name is valid */
if (!name || !strlen(name)) goto out;
- if (!(*parent) && xlate_proc_name(name, parent, &fn) != 0)
+ if (xlate_proc_name(name, parent, &fn) != 0)
goto out;
/* At this point there must not be any '/' characters beyond *fn */
@@ -682,9 +675,10 @@ struct proc_dir_entry *create_proc_entry(const char *name, mode_t mode,
return ent;
}
-struct proc_dir_entry *proc_create(const char *name, mode_t mode,
- struct proc_dir_entry *parent,
- const struct file_operations *proc_fops)
+struct proc_dir_entry *proc_create_data(const char *name, mode_t mode,
+ struct proc_dir_entry *parent,
+ const struct file_operations *proc_fops,
+ void *data)
{
struct proc_dir_entry *pde;
nlink_t nlink;
@@ -705,6 +699,7 @@ struct proc_dir_entry *proc_create(const char *name, mode_t mode,
if (!pde)
goto out;
pde->proc_fops = proc_fops;
+ pde->data = data;
if (proc_register(parent, pde) < 0)
goto out_free;
return pde;
@@ -734,55 +729,58 @@ void free_proc_entry(struct proc_dir_entry *de)
void remove_proc_entry(const char *name, struct proc_dir_entry *parent)
{
struct proc_dir_entry **p;
- struct proc_dir_entry *de;
+ struct proc_dir_entry *de = NULL;
const char *fn = name;
int len;
- if (!parent && xlate_proc_name(name, &parent, &fn) != 0)
- goto out;
+ if (xlate_proc_name(name, &parent, &fn) != 0)
+ return;
len = strlen(fn);
spin_lock(&proc_subdir_lock);
for (p = &parent->subdir; *p; p=&(*p)->next ) {
- if (!proc_match(len, fn, *p))
- continue;
- de = *p;
- *p = de->next;
- de->next = NULL;
-
- spin_lock(&de->pde_unload_lock);
- /*
- * Stop accepting new callers into module. If you're
- * dynamically allocating ->proc_fops, save a pointer somewhere.
- */
- de->proc_fops = NULL;
- /* Wait until all existing callers into module are done. */
- if (de->pde_users > 0) {
- DECLARE_COMPLETION_ONSTACK(c);
-
- if (!de->pde_unload_completion)
- de->pde_unload_completion = &c;
-
- spin_unlock(&de->pde_unload_lock);
- spin_unlock(&proc_subdir_lock);
+ if (proc_match(len, fn, *p)) {
+ de = *p;
+ *p = de->next;
+ de->next = NULL;
+ break;
+ }
+ }
+ spin_unlock(&proc_subdir_lock);
+ if (!de)
+ return;
- wait_for_completion(de->pde_unload_completion);
+ spin_lock(&de->pde_unload_lock);
+ /*
+ * Stop accepting new callers into module. If you're
+ * dynamically allocating ->proc_fops, save a pointer somewhere.
+ */
+ de->proc_fops = NULL;
+ /* Wait until all existing callers into module are done. */
+ if (de->pde_users > 0) {
+ DECLARE_COMPLETION_ONSTACK(c);
+
+ if (!de->pde_unload_completion)
+ de->pde_unload_completion = &c;
- spin_lock(&proc_subdir_lock);
- goto continue_removing;
- }
spin_unlock(&de->pde_unload_lock);
+ wait_for_completion(de->pde_unload_completion);
+
+ goto continue_removing;
+ }
+ spin_unlock(&de->pde_unload_lock);
+
continue_removing:
- if (S_ISDIR(de->mode))
- parent->nlink--;
- de->nlink = 0;
- WARN_ON(de->subdir);
- if (atomic_dec_and_test(&de->count))
- free_proc_entry(de);
- break;
+ if (S_ISDIR(de->mode))
+ parent->nlink--;
+ de->nlink = 0;
+ if (de->subdir) {
+ printk(KERN_WARNING "%s: removing non-empty directory "
+ "'%s/%s', leaking at least '%s'\n", __func__,
+ de->parent->name, de->name, de->subdir->name);
+ WARN_ON(1);
}
- spin_unlock(&proc_subdir_lock);
-out:
- return;
+ if (atomic_dec_and_test(&de->count))
+ free_proc_entry(de);
}
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 82b3a1b5a70b..6f4e8dc97da1 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -25,8 +25,7 @@
struct proc_dir_entry *de_get(struct proc_dir_entry *de)
{
- if (de)
- atomic_inc(&de->count);
+ atomic_inc(&de->count);
return de;
}
@@ -35,18 +34,16 @@ struct proc_dir_entry *de_get(struct proc_dir_entry *de)
*/
void de_put(struct proc_dir_entry *de)
{
- if (de) {
- lock_kernel();
- if (!atomic_read(&de->count)) {
- printk("de_put: entry %s already free!\n", de->name);
- unlock_kernel();
- return;
- }
-
- if (atomic_dec_and_test(&de->count))
- free_proc_entry(de);
+ lock_kernel();
+ if (!atomic_read(&de->count)) {
+ printk("de_put: entry %s already free!\n", de->name);
unlock_kernel();
+ return;
}
+
+ if (atomic_dec_and_test(&de->count))
+ free_proc_entry(de);
+ unlock_kernel();
}
/*
@@ -392,7 +389,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
{
struct inode * inode;
- if (de != NULL && !try_module_get(de->owner))
+ if (!try_module_get(de->owner))
goto out_mod;
inode = iget_locked(sb, ino);
@@ -402,30 +399,29 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
PROC_I(inode)->fd = 0;
PROC_I(inode)->pde = de;
- if (de) {
- if (de->mode) {
- inode->i_mode = de->mode;
- inode->i_uid = de->uid;
- inode->i_gid = de->gid;
- }
- if (de->size)
- inode->i_size = de->size;
- if (de->nlink)
- inode->i_nlink = de->nlink;
- if (de->proc_iops)
- inode->i_op = de->proc_iops;
- if (de->proc_fops) {
- if (S_ISREG(inode->i_mode)) {
+
+ if (de->mode) {
+ inode->i_mode = de->mode;
+ inode->i_uid = de->uid;
+ inode->i_gid = de->gid;
+ }
+ if (de->size)
+ inode->i_size = de->size;
+ if (de->nlink)
+ inode->i_nlink = de->nlink;
+ if (de->proc_iops)
+ inode->i_op = de->proc_iops;
+ if (de->proc_fops) {
+ if (S_ISREG(inode->i_mode)) {
#ifdef CONFIG_COMPAT
- if (!de->proc_fops->compat_ioctl)
- inode->i_fop =
- &proc_reg_file_ops_no_compat;
- else
+ if (!de->proc_fops->compat_ioctl)
+ inode->i_fop =
+ &proc_reg_file_ops_no_compat;
+ else
#endif
- inode->i_fop = &proc_reg_file_ops;
- } else {
- inode->i_fop = de->proc_fops;
- }
+ inode->i_fop = &proc_reg_file_ops;
+ } else {
+ inode->i_fop = de->proc_fops;
}
}
unlock_new_inode(inode);
@@ -433,8 +429,7 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
return inode;
out_ino:
- if (de != NULL)
- module_put(de->owner);
+ module_put(de->owner);
out_mod:
return NULL;
}
diff --git a/fs/proc/internal.h b/fs/proc/internal.h
index bc72f5c8c47d..28cbca805905 100644
--- a/fs/proc/internal.h
+++ b/fs/proc/internal.h
@@ -11,6 +11,7 @@
#include <linux/proc_fs.h>
+extern struct proc_dir_entry proc_root;
#ifdef CONFIG_PROC_SYSCTL
extern int proc_sys_init(void);
#else
@@ -46,9 +47,6 @@ extern int nommu_vma_show(struct seq_file *, struct vm_area_struct *);
extern int maps_protect;
-extern void create_seq_entry(char *name, mode_t mode,
- const struct file_operations *f);
-extern int proc_exe_link(struct inode *, struct path *);
extern int proc_tid_stat(struct seq_file *m, struct pid_namespace *ns,
struct pid *pid, struct task_struct *task);
extern int proc_tgid_stat(struct seq_file *m, struct pid_namespace *ns,
diff --git a/fs/proc/nommu.c b/fs/proc/nommu.c
index 941e95114b5a..79ecd281d2cb 100644
--- a/fs/proc/nommu.c
+++ b/fs/proc/nommu.c
@@ -137,7 +137,7 @@ static const struct file_operations proc_nommu_vma_list_operations = {
static int __init proc_nommu_init(void)
{
- create_seq_entry("maps", S_IRUGO, &proc_nommu_vma_list_operations);
+ proc_create("maps", S_IRUGO, NULL, &proc_nommu_vma_list_operations);
return 0;
}
diff --git a/fs/proc/proc_misc.c b/fs/proc/proc_misc.c
index 441a32f0e5f2..48bcf20cec2f 100644
--- a/fs/proc/proc_misc.c
+++ b/fs/proc/proc_misc.c
@@ -826,14 +826,6 @@ static struct file_operations proc_kpageflags_operations = {
struct proc_dir_entry *proc_root_kcore;
-void create_seq_entry(char *name, mode_t mode, const struct file_operations *f)
-{
- struct proc_dir_entry *entry;
- entry = create_proc_entry(name, mode, NULL);
- if (entry)
- entry->proc_fops = f;
-}
-
void __init proc_misc_init(void)
{
static struct {
@@ -862,66 +854,52 @@ void __init proc_misc_init(void)
/* And now for trickier ones */
#ifdef CONFIG_PRINTK
- {
- struct proc_dir_entry *entry;
- entry = create_proc_entry("kmsg", S_IRUSR, &proc_root);
- if (entry)
- entry->proc_fops = &proc_kmsg_operations;
- }
+ proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations);
#endif
- create_seq_entry("locks", 0, &proc_locks_operations);
- create_seq_entry("devices", 0, &proc_devinfo_operations);
- create_seq_entry("cpuinfo", 0, &proc_cpuinfo_operations);
+ proc_create("locks", 0, NULL, &proc_locks_operations);
+ proc_create("devices", 0, NULL, &proc_devinfo_operations);
+ proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations);
#ifdef CONFIG_BLOCK
- create_seq_entry("partitions", 0, &proc_partitions_operations);
+ proc_create("partitions", 0, NULL, &proc_partitions_operations);
#endif
- create_seq_entry("stat", 0, &proc_stat_operations);
- create_seq_entry("interrupts", 0, &proc_interrupts_operations);
+ proc_create("stat", 0, NULL, &proc_stat_operations);
+ proc_create("interrupts", 0, NULL, &proc_interrupts_operations);
#ifdef CONFIG_SLABINFO
- create_seq_entry("slabinfo",S_IWUSR|S_IRUGO,&proc_slabinfo_operations);
+ proc_create("slabinfo",S_IWUSR|S_IRUGO,NULL,&proc_slabinfo_operations);
#ifdef CONFIG_DEBUG_SLAB_LEAK
- create_seq_entry("slab_allocators", 0 ,&proc_slabstats_operations);
+ proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations);
#endif
#endif
#ifdef CONFIG_MMU
proc_create("vmallocinfo", S_IRUSR, NULL, &proc_vmalloc_operations);
#endif
- create_seq_entry("buddyinfo",S_IRUGO, &fragmentation_file_operations);
- create_seq_entry("pagetypeinfo", S_IRUGO, &pagetypeinfo_file_ops);
- create_seq_entry("vmstat",S_IRUGO, &proc_vmstat_file_operations);
- create_seq_entry("zoneinfo",S_IRUGO, &proc_zoneinfo_file_operations);
+ proc_create("buddyinfo", S_IRUGO, NULL, &fragmentation_file_operations);
+ proc_create("pagetypeinfo", S_IRUGO, NULL, &pagetypeinfo_file_ops);
+ proc_create("vmstat", S_IRUGO, NULL, &proc_vmstat_file_operations);
+ proc_create("zoneinfo", S_IRUGO, NULL, &proc_zoneinfo_file_operations);
#ifdef CONFIG_BLOCK
- create_seq_entry("diskstats", 0, &proc_diskstats_operations);
+ proc_create("diskstats", 0, NULL, &proc_diskstats_operations);
#endif
#ifdef CONFIG_MODULES
- create_seq_entry("modules", 0, &proc_modules_operations);
+ proc_create("modules", 0, NULL, &proc_modules_operations);
#endif
#ifdef CONFIG_SCHEDSTATS
- create_seq_entry("schedstat", 0, &proc_schedstat_operations);
+ proc_create("schedstat", 0, NULL, &proc_schedstat_operations);
#endif
#ifdef CONFIG_PROC_KCORE
- proc_root_kcore = create_proc_entry("kcore", S_IRUSR, NULL);
- if (proc_root_kcore) {
- proc_root_kcore->proc_fops = &proc_kcore_operations;
+ proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, &proc_kcore_operations);
+ if (proc_root_kcore)
proc_root_kcore->size =
(size_t)high_memory - PAGE_OFFSET + PAGE_SIZE;
- }
#endif
#ifdef CONFIG_PROC_PAGE_MONITOR
- create_seq_entry("kpagecount", S_IRUSR, &proc_kpagecount_operations);
- create_seq_entry("kpageflags", S_IRUSR, &proc_kpageflags_operations);
+ proc_create("kpagecount", S_IRUSR, NULL, &proc_kpagecount_operations);
+ proc_create("kpageflags", S_IRUSR, NULL, &proc_kpageflags_operations);
#endif
#ifdef CONFIG_PROC_VMCORE
- proc_vmcore = create_proc_entry("vmcore", S_IRUSR, NULL);
- if (proc_vmcore)
- proc_vmcore->proc_fops = &proc_vmcore_operations;
+ proc_vmcore = proc_create("vmcore", S_IRUSR, NULL, &proc_vmcore_operations);
#endif
#ifdef CONFIG_MAGIC_SYSRQ
- {
- struct proc_dir_entry *entry;
- entry = create_proc_entry("sysrq-trigger", S_IWUSR, NULL);
- if (entry)
- entry->proc_fops = &proc_sysrq_trigger_operations;
- }
+ proc_create("sysrq-trigger", S_IWUSR, NULL, &proc_sysrq_trigger_operations);
#endif
}
diff --git a/fs/proc/proc_sysctl.c b/fs/proc/proc_sysctl.c
index 614c34b6d1c2..5acc001d49f6 100644
--- a/fs/proc/proc_sysctl.c
+++ b/fs/proc/proc_sysctl.c
@@ -165,8 +165,8 @@ out:
return err;
}
-static ssize_t proc_sys_read(struct file *filp, char __user *buf,
- size_t count, loff_t *ppos)
+static ssize_t proc_sys_call_handler(struct file *filp, void __user *buf,
+ size_t count, loff_t *ppos, int write)
{
struct dentry *dentry = filp->f_dentry;
struct ctl_table_header *head;
@@ -190,12 +190,12 @@ static ssize_t proc_sys_read(struct file *filp, char __user *buf,
* and won't be until we finish.
*/
error = -EPERM;
- if (sysctl_perm(table, MAY_READ))
+ if (sysctl_perm(head->root, table, write ? MAY_WRITE : MAY_READ))
goto out;
/* careful: calling conventions are nasty here */
res = count;
- error = table->proc_handler(table, 0, filp, buf, &res, ppos);
+ error = table->proc_handler(table, write, filp, buf, &res, ppos);
if (!error)
error = res;
out:
@@ -204,44 +204,16 @@ out:
return error;
}
-static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
+static ssize_t proc_sys_read(struct file *filp, char __user *buf,
size_t count, loff_t *ppos)
{
- struct dentry *dentry = filp->f_dentry;
- struct ctl_table_header *head;
- struct ctl_table *table;
- ssize_t error;
- size_t res;
-
- table = do_proc_sys_lookup(dentry->d_parent, &dentry->d_name, &head);
- /* Has the sysctl entry disappeared on us? */
- error = -ENOENT;
- if (!table)
- goto out;
-
- /* Has the sysctl entry been replaced by a directory? */
- error = -EISDIR;
- if (!table->proc_handler)
- goto out;
-
- /*
- * At this point we know that the sysctl was not unregistered
- * and won't be until we finish.
- */
- error = -EPERM;
- if (sysctl_perm(table, MAY_WRITE))
- goto out;
-
- /* careful: calling conventions are nasty here */
- res = count;
- error = table->proc_handler(table, 1, filp, (char __user *)buf,
- &res, ppos);
- if (!error)
- error = res;
-out:
- sysctl_head_finish(head);
+ return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 0);
+}
- return error;
+static ssize_t proc_sys_write(struct file *filp, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ return proc_sys_call_handler(filp, (void __user *)buf, count, ppos, 1);
}
@@ -416,7 +388,7 @@ static int proc_sys_permission(struct inode *inode, int mask, struct nameidata *
goto out;
/* Use the permissions on the sysctl table entry */
- error = sysctl_perm(table, mask);
+ error = sysctl_perm(head->root, table, mask);
out:
sysctl_head_finish(head);
return error;
diff --git a/fs/proc/proc_tty.c b/fs/proc/proc_tty.c
index 49816e00b51a..ac26ccc25f42 100644
--- a/fs/proc/proc_tty.c
+++ b/fs/proc/proc_tty.c
@@ -5,7 +5,7 @@
*/
#include <asm/uaccess.h>
-
+#include <linux/module.h>
#include <linux/init.h>
#include <linux/errno.h>
#include <linux/time.h>
@@ -136,39 +136,54 @@ static const struct file_operations proc_tty_drivers_operations = {
.release = seq_release,
};
-/*
- * This is the handler for /proc/tty/ldiscs
- */
-static int tty_ldiscs_read_proc(char *page, char **start, off_t off,
- int count, int *eof, void *data)
+static void * tty_ldiscs_seq_start(struct seq_file *m, loff_t *pos)
{
- int i;
- int len = 0;
- off_t begin = 0;
+ return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void * tty_ldiscs_seq_next(struct seq_file *m, void *v, loff_t *pos)
+{
+ (*pos)++;
+ return (*pos < NR_LDISCS) ? pos : NULL;
+}
+
+static void tty_ldiscs_seq_stop(struct seq_file *m, void *v)
+{
+}
+
+static int tty_ldiscs_seq_show(struct seq_file *m, void *v)
+{
+ int i = *(loff_t *)v;
struct tty_ldisc *ld;
- for (i=0; i < NR_LDISCS; i++) {
- ld = tty_ldisc_get(i);
- if (ld == NULL)
- continue;
- len += sprintf(page+len, "%-10s %2d\n",
- ld->name ? ld->name : "???", i);
- tty_ldisc_put(i);
- if (len+begin > off+count)
- break;
- if (len+begin < off) {
- begin += len;
- len = 0;
- }
- }
- if (i >= NR_LDISCS)
- *eof = 1;
- if (off >= len+begin)
+ ld = tty_ldisc_get(i);
+ if (ld == NULL)
return 0;
- *start = page + (off-begin);
- return ((count < begin+len-off) ? count : begin+len-off);
+ seq_printf(m, "%-10s %2d\n", ld->name ? ld->name : "???", i);
+ tty_ldisc_put(i);
+ return 0;
+}
+
+static const struct seq_operations tty_ldiscs_seq_ops = {
+ .start = tty_ldiscs_seq_start,
+ .next = tty_ldiscs_seq_next,
+ .stop = tty_ldiscs_seq_stop,
+ .show = tty_ldiscs_seq_show,
+};
+
+static int proc_tty_ldiscs_open(struct inode *inode, struct file *file)
+{
+ return seq_open(file, &tty_ldiscs_seq_ops);
}
+static const struct file_operations tty_ldiscs_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_tty_ldiscs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = seq_release,
+};
+
/*
* This function is called by tty_register_driver() to handle
* registering the driver's /proc handler into /proc/tty/driver/<foo>
@@ -214,7 +229,6 @@ void proc_tty_unregister_driver(struct tty_driver *driver)
*/
void __init proc_tty_init(void)
{
- struct proc_dir_entry *entry;
if (!proc_mkdir("tty", NULL))
return;
proc_tty_ldisc = proc_mkdir("tty/ldisc", NULL);
@@ -224,10 +238,7 @@ void __init proc_tty_init(void)
* password lengths and inter-keystroke timings during password
* entry.
*/
- proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR | S_IXUSR, NULL);
-
- create_proc_read_entry("tty/ldiscs", 0, NULL, tty_ldiscs_read_proc, NULL);
- entry = create_proc_entry("tty/drivers", 0, NULL);
- if (entry)
- entry->proc_fops = &proc_tty_drivers_operations;
+ proc_tty_driver = proc_mkdir_mode("tty/driver", S_IRUSR|S_IXUSR, NULL);
+ proc_create("tty/ldiscs", 0, NULL, &tty_ldiscs_proc_fops);
+ proc_create("tty/drivers", 0, NULL, &proc_tty_drivers_operations);
}
diff --git a/fs/proc/root.c b/fs/proc/root.c
index ef0fb57fc9ef..95117538a4f6 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -22,8 +22,6 @@
#include "internal.h"
-struct proc_dir_entry *proc_bus, *proc_root_fs, *proc_root_driver;
-
static int proc_test_super(struct super_block *sb, void *data)
{
return sb->s_fs_info == data;
@@ -126,8 +124,8 @@ void __init proc_root_init(void)
#ifdef CONFIG_SYSVIPC
proc_mkdir("sysvipc", NULL);
#endif
- proc_root_fs = proc_mkdir("fs", NULL);
- proc_root_driver = proc_mkdir("driver", NULL);
+ proc_mkdir("fs", NULL);
+ proc_mkdir("driver", NULL);
proc_mkdir("fs/nfsd", NULL); /* somewhere for the nfsd filesystem to be mounted */
#if defined(CONFIG_SUN_OPENPROMFS) || defined(CONFIG_SUN_OPENPROMFS_MODULE)
/* just give it a mountpoint */
@@ -137,7 +135,7 @@ void __init proc_root_init(void)
#ifdef CONFIG_PROC_DEVICETREE
proc_device_tree_init();
#endif
- proc_bus = proc_mkdir("bus", NULL);
+ proc_mkdir("bus", NULL);
proc_sys_init();
}
@@ -232,9 +230,5 @@ void pid_ns_release_proc(struct pid_namespace *ns)
EXPORT_SYMBOL(proc_symlink);
EXPORT_SYMBOL(proc_mkdir);
EXPORT_SYMBOL(create_proc_entry);
-EXPORT_SYMBOL(proc_create);
+EXPORT_SYMBOL(proc_create_data);
EXPORT_SYMBOL(remove_proc_entry);
-EXPORT_SYMBOL(proc_root);
-EXPORT_SYMBOL(proc_root_fs);
-EXPORT_SYMBOL(proc_bus);
-EXPORT_SYMBOL(proc_root_driver);
diff --git a/fs/proc/task_mmu.c b/fs/proc/task_mmu.c
index 7415eeb7cc3a..e2b8e769f510 100644
--- a/fs/proc/task_mmu.c
+++ b/fs/proc/task_mmu.c
@@ -75,40 +75,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
return mm->total_vm;
}
-int proc_exe_link(struct inode *inode, struct path *path)
-{
- struct vm_area_struct * vma;
- int result = -ENOENT;
- struct task_struct *task = get_proc_task(inode);
- struct mm_struct * mm = NULL;
-
- if (task) {
- mm = get_task_mm(task);
- put_task_struct(task);
- }
- if (!mm)
- goto out;
- down_read(&mm->mmap_sem);
-
- vma = mm->mmap;
- while (vma) {
- if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file)
- break;
- vma = vma->vm_next;
- }
-
- if (vma) {
- *path = vma->vm_file->f_path;
- path_get(&vma->vm_file->f_path);
- result = 0;
- }
-
- up_read(&mm->mmap_sem);
- mmput(mm);
-out:
- return result;
-}
-
static void pad_len_spaces(struct seq_file *m, int len)
{
len = 25 + sizeof(void*) * 6 - len;
diff --git a/fs/proc/task_nommu.c b/fs/proc/task_nommu.c
index 8011528518bd..4b733f108455 100644
--- a/fs/proc/task_nommu.c
+++ b/fs/proc/task_nommu.c
@@ -103,40 +103,6 @@ int task_statm(struct mm_struct *mm, int *shared, int *text,
return size;
}
-int proc_exe_link(struct inode *inode, struct path *path)
-{
- struct vm_list_struct *vml;
- struct vm_area_struct *vma;
- struct task_struct *task = get_proc_task(inode);
- struct mm_struct *mm = get_task_mm(task);
- int result = -ENOENT;
-
- if (!mm)
- goto out;
- down_read(&mm->mmap_sem);
-
- vml = mm->context.vmlist;
- vma = NULL;
- while (vml) {
- if ((vml->vma->vm_flags & VM_EXECUTABLE) && vml->vma->vm_file) {
- vma = vml->vma;
- break;
- }
- vml = vml->next;
- }
-
- if (vma) {
- *path = vma->vm_file->f_path;
- path_get(&vma->vm_file->f_path);
- result = 0;
- }
-
- up_read(&mm->mmap_sem);
- mmput(mm);
-out:
- return result;
-}
-
/*
* display mapping lines for a particular process's /proc/pid/maps
*/
diff --git a/fs/ramfs/file-mmu.c b/fs/ramfs/file-mmu.c
index b41a514b0976..9590b9024300 100644
--- a/fs/ramfs/file-mmu.c
+++ b/fs/ramfs/file-mmu.c
@@ -26,6 +26,9 @@
#include <linux/fs.h>
#include <linux/mm.h>
+#include <linux/ramfs.h>
+
+#include "internal.h"
const struct address_space_operations ramfs_aops = {
.readpage = simple_readpage,
diff --git a/fs/ramfs/internal.h b/fs/ramfs/internal.h
index af7cc074a476..6b330639b51d 100644
--- a/fs/ramfs/internal.h
+++ b/fs/ramfs/internal.h
@@ -11,5 +11,4 @@
extern const struct address_space_operations ramfs_aops;
-extern const struct file_operations ramfs_file_operations;
extern const struct inode_operations ramfs_file_inode_operations;
diff --git a/fs/reiserfs/procfs.c b/fs/reiserfs/procfs.c
index 8f86c52b30d8..b9dbeeca7049 100644
--- a/fs/reiserfs/procfs.c
+++ b/fs/reiserfs/procfs.c
@@ -467,6 +467,7 @@ static const struct file_operations r_file_operations = {
.read = seq_read,
.llseek = seq_lseek,
.release = seq_release,
+ .owner = THIS_MODULE,
};
static struct proc_dir_entry *proc_info_root = NULL;
@@ -475,12 +476,8 @@ static const char proc_info_root_name[] = "fs/reiserfs";
static void add_file(struct super_block *sb, char *name,
int (*func) (struct seq_file *, struct super_block *))
{
- struct proc_dir_entry *de;
- de = create_proc_entry(name, 0, REISERFS_SB(sb)->procdir);
- if (de) {
- de->data = func;
- de->proc_fops = &r_file_operations;
- }
+ proc_create_data(name, 0, REISERFS_SB(sb)->procdir,
+ &r_file_operations, func);
}
int reiserfs_proc_info_init(struct super_block *sb)
diff --git a/fs/super.c b/fs/super.c
index a5a4aca7e22f..453877c5697b 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -117,7 +117,7 @@ static inline void destroy_super(struct super_block *s)
* Drop a superblock's refcount. Returns non-zero if the superblock was
* destroyed. The caller must hold sb_lock.
*/
-int __put_super(struct super_block *sb)
+static int __put_super(struct super_block *sb)
{
int ret = 0;
diff --git a/fs/sync.c b/fs/sync.c
index 7cd005ea7639..228e17b5e9ee 100644
--- a/fs/sync.c
+++ b/fs/sync.c
@@ -64,7 +64,7 @@ int file_fsync(struct file *filp, struct dentry *dentry, int datasync)
/* sync the superblock to buffers */
sb = inode->i_sb;
lock_super(sb);
- if (sb->s_op->write_super)
+ if (sb->s_dirt && sb->s_op->write_super)
sb->s_op->write_super(sb);
unlock_super(sb);
diff --git a/fs/timerfd.c b/fs/timerfd.c
index 10c80b59ec4b..5400524e9cb1 100644
--- a/fs/timerfd.c
+++ b/fs/timerfd.c
@@ -20,6 +20,7 @@
#include <linux/hrtimer.h>
#include <linux/anon_inodes.h>
#include <linux/timerfd.h>
+#include <linux/syscalls.h>
struct timerfd_ctx {
struct hrtimer tmr;
diff --git a/fs/xattr.c b/fs/xattr.c
index 89a942f07e1b..4706a8b1f495 100644
--- a/fs/xattr.c
+++ b/fs/xattr.c
@@ -67,7 +67,7 @@ xattr_permission(struct inode *inode, const char *name, int mask)
}
int
-vfs_setxattr(struct dentry *dentry, char *name, void *value,
+vfs_setxattr(struct dentry *dentry, const char *name, const void *value,
size_t size, int flags)
{
struct inode *inode = dentry->d_inode;
@@ -131,7 +131,7 @@ out_noalloc:
EXPORT_SYMBOL_GPL(xattr_getsecurity);
ssize_t
-vfs_getxattr(struct dentry *dentry, char *name, void *value, size_t size)
+vfs_getxattr(struct dentry *dentry, const char *name, void *value, size_t size)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -187,7 +187,7 @@ vfs_listxattr(struct dentry *d, char *list, size_t size)
EXPORT_SYMBOL_GPL(vfs_listxattr);
int
-vfs_removexattr(struct dentry *dentry, char *name)
+vfs_removexattr(struct dentry *dentry, const char *name)
{
struct inode *inode = dentry->d_inode;
int error;
@@ -218,7 +218,7 @@ EXPORT_SYMBOL_GPL(vfs_removexattr);
* Extended attribute SET operations
*/
static long
-setxattr(struct dentry *d, char __user *name, void __user *value,
+setxattr(struct dentry *d, const char __user *name, const void __user *value,
size_t size, int flags)
{
int error;
@@ -252,8 +252,8 @@ setxattr(struct dentry *d, char __user *name, void __user *value,
}
asmlinkage long
-sys_setxattr(char __user *path, char __user *name, void __user *value,
- size_t size, int flags)
+sys_setxattr(const char __user *path, const char __user *name,
+ const void __user *value, size_t size, int flags)
{
struct nameidata nd;
int error;
@@ -271,8 +271,8 @@ sys_setxattr(char __user *path, char __user *name, void __user *value,
}
asmlinkage long
-sys_lsetxattr(char __user *path, char __user *name, void __user *value,
- size_t size, int flags)
+sys_lsetxattr(const char __user *path, const char __user *name,
+ const void __user *value, size_t size, int flags)
{
struct nameidata nd;
int error;
@@ -290,7 +290,7 @@ sys_lsetxattr(char __user *path, char __user *name, void __user *value,
}
asmlinkage long
-sys_fsetxattr(int fd, char __user *name, void __user *value,
+sys_fsetxattr(int fd, const char __user *name, const void __user *value,
size_t size, int flags)
{
struct file *f;
@@ -315,7 +315,8 @@ sys_fsetxattr(int fd, char __user *name, void __user *value,
* Extended attribute GET operations
*/
static ssize_t
-getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
+getxattr(struct dentry *d, const char __user *name, void __user *value,
+ size_t size)
{
ssize_t error;
void *kvalue = NULL;
@@ -349,8 +350,8 @@ getxattr(struct dentry *d, char __user *name, void __user *value, size_t size)
}
asmlinkage ssize_t
-sys_getxattr(char __user *path, char __user *name, void __user *value,
- size_t size)
+sys_getxattr(const char __user *path, const char __user *name,
+ void __user *value, size_t size)
{
struct nameidata nd;
ssize_t error;
@@ -364,7 +365,7 @@ sys_getxattr(char __user *path, char __user *name, void __user *value,
}
asmlinkage ssize_t
-sys_lgetxattr(char __user *path, char __user *name, void __user *value,
+sys_lgetxattr(const char __user *path, const char __user *name, void __user *value,
size_t size)
{
struct nameidata nd;
@@ -379,7 +380,7 @@ sys_lgetxattr(char __user *path, char __user *name, void __user *value,
}
asmlinkage ssize_t
-sys_fgetxattr(int fd, char __user *name, void __user *value, size_t size)
+sys_fgetxattr(int fd, const char __user *name, void __user *value, size_t size)
{
struct file *f;
ssize_t error = -EBADF;
@@ -424,7 +425,7 @@ listxattr(struct dentry *d, char __user *list, size_t size)
}
asmlinkage ssize_t
-sys_listxattr(char __user *path, char __user *list, size_t size)
+sys_listxattr(const char __user *path, char __user *list, size_t size)
{
struct nameidata nd;
ssize_t error;
@@ -438,7 +439,7 @@ sys_listxattr(char __user *path, char __user *list, size_t size)
}
asmlinkage ssize_t
-sys_llistxattr(char __user *path, char __user *list, size_t size)
+sys_llistxattr(const char __user *path, char __user *list, size_t size)
{
struct nameidata nd;
ssize_t error;
@@ -470,7 +471,7 @@ sys_flistxattr(int fd, char __user *list, size_t size)
* Extended attribute REMOVE operations
*/
static long
-removexattr(struct dentry *d, char __user *name)
+removexattr(struct dentry *d, const char __user *name)
{
int error;
char kname[XATTR_NAME_MAX + 1];
@@ -485,7 +486,7 @@ removexattr(struct dentry *d, char __user *name)
}
asmlinkage long
-sys_removexattr(char __user *path, char __user *name)
+sys_removexattr(const char __user *path, const char __user *name)
{
struct nameidata nd;
int error;
@@ -503,7 +504,7 @@ sys_removexattr(char __user *path, char __user *name)
}
asmlinkage long
-sys_lremovexattr(char __user *path, char __user *name)
+sys_lremovexattr(const char __user *path, const char __user *name)
{
struct nameidata nd;
int error;
@@ -521,7 +522,7 @@ sys_lremovexattr(char __user *path, char __user *name)
}
asmlinkage long
-sys_fremovexattr(int fd, char __user *name)
+sys_fremovexattr(int fd, const char __user *name)
{
struct file *f;
struct dentry *dentry;