Merge branch 'android-4.4' of https://android.googlesource.com/kernel/common
authorHuang, Tao <huangtao@rock-chips.com>
Tue, 29 Mar 2016 11:45:19 +0000 (19:45 +0800)
committerHuang, Tao <huangtao@rock-chips.com>
Tue, 29 Mar 2016 11:45:19 +0000 (19:45 +0800)
* android-4.4: (34 commits)
  sdcardfs: remove unneeded __init and __exit
  sdcardfs: Remove unused code
  fs: Export d_absolute_path
  sdcardfs: remove effectless config option
  inotify: Fix erroneous update of bit count
  fs: sdcardfs: Declare LOOKUP_CASE_INSENSITIVE unconditionally
  trace: cpufreq: fix typo in min/max cpufreq
  sdcardfs: Add support for d_canonical_path
  vfs: add d_canonical_path for stacked filesystem support
  sdcardfs: Bring up to date with Android M permissions:
  Changed type-casting in packagelist management
  Port of sdcardfs to 4.4
  Included sdcardfs source code for kernel 3.0
  ANDROID: usb: gadget: Add support for MTP OS desc
  CHROMIUM: usb: gadget: f_accessory: add .raw_request callback
  CHROMIUM: usb: gadget: audio_source: add .free_func callback
  CHROMIUM: usb: gadget: f_mtp: fix usb_ss_ep_comp_descriptor
  CHROMIUM: usb: gadget: f_mtp: Add SuperSpeed support
  FROMLIST: mmc: block: fix ABI regression of mmc_blk_ioctl
  FROMLIST: mm: ASLR: use get_random_long()
  ...

Change-Id: I88fa8a7f6bfc80bee98503b9ede0fee08d62814c

44 files changed:
arch/arm/mm/mmap.c
arch/arm64/mm/mmap.c
arch/mips/mm/mmap.c
arch/powerpc/kernel/process.c
arch/powerpc/mm/mmap.c
arch/sparc/kernel/sys_sparc_64.c
arch/x86/mm/mmap.c
drivers/base/power/main.c
drivers/char/random.c
drivers/hid/hid-sensor-hub.c
drivers/md/dm-crypt.c
drivers/misc/uid_stat.c
drivers/mmc/card/block.c
drivers/usb/gadget/function/f_accessory.c
drivers/usb/gadget/function/f_audio_source.c
drivers/usb/gadget/function/f_mtp.c
drivers/usb/gadget/function/u_ether.c
drivers/video/adf/Kconfig
fs/Kconfig
fs/Makefile
fs/binfmt_elf.c
fs/dcache.c
fs/notify/inotify/inotify_user.c
fs/pstore/ram.c
fs/sdcardfs/Kconfig [new file with mode: 0644]
fs/sdcardfs/Makefile [new file with mode: 0644]
fs/sdcardfs/dentry.c [new file with mode: 0644]
fs/sdcardfs/derived_perm.c [new file with mode: 0644]
fs/sdcardfs/file.c [new file with mode: 0644]
fs/sdcardfs/inode.c [new file with mode: 0644]
fs/sdcardfs/lookup.c [new file with mode: 0644]
fs/sdcardfs/main.c [new file with mode: 0644]
fs/sdcardfs/mmap.c [new file with mode: 0644]
fs/sdcardfs/multiuser.h [new file with mode: 0644]
fs/sdcardfs/packagelist.c [new file with mode: 0644]
fs/sdcardfs/sdcardfs.h [new file with mode: 0644]
fs/sdcardfs/super.c [new file with mode: 0644]
include/linux/dcache.h
include/linux/namei.h
include/linux/random.h
include/linux/wakeup_reason.h
include/trace/events/power.h
include/uapi/linux/magic.h
kernel/power/Kconfig

index 4b4058db0781f63e307d4f5101a74d5330ddf337..66353caa35b9f78fa2aa4754dea3ce813593303f 100644 (file)
@@ -173,7 +173,7 @@ unsigned long arch_mmap_rnd(void)
 {
        unsigned long rnd;
 
-       rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+       rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 
        return rnd << PAGE_SHIFT;
 }
index 4c893b5189ddd027537511c5daaca70f158577c4..232f787a088ae8e992c52cba450159a43a900174 100644 (file)
@@ -53,10 +53,10 @@ unsigned long arch_mmap_rnd(void)
 
 #ifdef CONFIG_COMPAT
        if (test_thread_flag(TIF_32BIT))
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_compat_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
        else
 #endif
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
        return rnd << PAGE_SHIFT;
 }
 
index 5c81fdd032c3b1269549f27e27348e9606eb5424..353037699512ca5515b11ce8fb2c808eb6386c78 100644 (file)
@@ -146,7 +146,7 @@ unsigned long arch_mmap_rnd(void)
 {
        unsigned long rnd;
 
-       rnd = (unsigned long)get_random_int();
+       rnd = get_random_long();
        rnd <<= PAGE_SHIFT;
        if (TASK_IS_32BIT_ADDR)
                rnd &= 0xfffffful;
@@ -174,7 +174,7 @@ void arch_pick_mmap_layout(struct mm_struct *mm)
 
 static inline unsigned long brk_rnd(void)
 {
-       unsigned long rnd = get_random_int();
+       unsigned long rnd = get_random_long();
 
        rnd = rnd << PAGE_SHIFT;
        /* 8MB for 32bit, 256MB for 64bit */
index ef2ad2d682dae74f97598fa4a789b59058368a29..36795d1e75586aa523f2c55ffabc09baeb1562f1 100644 (file)
@@ -1659,9 +1659,9 @@ static inline unsigned long brk_rnd(void)
 
        /* 8MB for 32bit, 1GB for 64bit */
        if (is_32bit_task())
-               rnd = (long)(get_random_int() % (1<<(23-PAGE_SHIFT)));
+               rnd = (get_random_long() % (1UL<<(23-PAGE_SHIFT)));
        else
-               rnd = (long)(get_random_int() % (1<<(30-PAGE_SHIFT)));
+               rnd = (get_random_long() % (1UL<<(30-PAGE_SHIFT)));
 
        return rnd << PAGE_SHIFT;
 }
index 0f0502e12f6c4c8accbe7fc28eb4db08158decfb..4087705ba90f34241200e2f30765794ea6b74b55 100644 (file)
@@ -59,9 +59,9 @@ unsigned long arch_mmap_rnd(void)
 
        /* 8MB for 32bit, 1GB for 64bit */
        if (is_32bit_task())
-               rnd = (unsigned long)get_random_int() % (1<<(23-PAGE_SHIFT));
+               rnd = get_random_long() % (1<<(23-PAGE_SHIFT));
        else
-               rnd = (unsigned long)get_random_int() % (1<<(30-PAGE_SHIFT));
+               rnd = get_random_long() % (1UL<<(30-PAGE_SHIFT));
 
        return rnd << PAGE_SHIFT;
 }
index c690c8e16a96ef2758fca4e9af8080ec7af6c17a..b489e9759518182b6a3884935e5a1c22b1af3524 100644 (file)
@@ -264,7 +264,7 @@ static unsigned long mmap_rnd(void)
        unsigned long rnd = 0UL;
 
        if (current->flags & PF_RANDOMIZE) {
-               unsigned long val = get_random_int();
+               unsigned long val = get_random_long();
                if (test_thread_flag(TIF_32BIT))
                        rnd = (val % (1UL << (23UL-PAGE_SHIFT)));
                else
index 96bd1e2bffafb3b8ffbc28906a2998ad992d50e8..72bb52f93c3d619d0dc6c0355b7ab293a24c3199 100644 (file)
@@ -71,12 +71,12 @@ unsigned long arch_mmap_rnd(void)
 
        if (mmap_is_ia32())
 #ifdef CONFIG_COMPAT
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_compat_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_compat_bits) - 1);
 #else
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 #endif
        else
-               rnd = (unsigned long)get_random_int() & ((1 << mmap_rnd_bits) - 1);
+               rnd = get_random_long() & ((1UL << mmap_rnd_bits) - 1);
 
        return rnd << PAGE_SHIFT;
 }
index a54d810f29666292845380961eed247d068d4f15..6ed8b932662967f37f3826a1da56cf621c6eddbb 100644 (file)
@@ -35,6 +35,8 @@
 #include <linux/timer.h>
 #include <linux/wakeup_reason.h>
 
+#include <asm/current.h>
+
 #include "../base.h"
 #include "power.h"
 
@@ -1412,7 +1414,7 @@ static int __device_suspend(struct device *dev, pm_message_t state, bool async)
                goto Complete;
        
        data.dev = dev;
-       data.tsk = get_current();
+       data.tsk = current;
        init_timer_on_stack(&timer);
        timer.expires = jiffies + HZ * 12;
        timer.function = dpm_drv_timeout;
index d0da5d852d41e5588bb9bd192431a403a9696848..b583e53366306db870a0d61918156f41985f075e 100644 (file)
@@ -1818,6 +1818,28 @@ unsigned int get_random_int(void)
 }
 EXPORT_SYMBOL(get_random_int);
 
+/*
+ * Same as get_random_int(), but returns unsigned long.
+ */
+unsigned long get_random_long(void)
+{
+       __u32 *hash;
+       unsigned long ret;
+
+       if (arch_get_random_long(&ret))
+               return ret;
+
+       hash = get_cpu_var(get_random_int_hash);
+
+       hash[0] += current->pid + jiffies + random_get_entropy();
+       md5_transform(hash, random_int_secret);
+       ret = *(unsigned long *)hash;
+       put_cpu_var(get_random_int_hash);
+
+       return ret;
+}
+EXPORT_SYMBOL(get_random_long);
+
 /*
  * randomize_range() returns a start address such that
  *
index 92870cdb52d946a7408463a5b249129befd5e91d..8efaa88329aa3d40296fb5ff29aed1e20e2d1d37 100644 (file)
@@ -218,7 +218,8 @@ int sensor_hub_set_feature(struct hid_sensor_hub_device *hsdev, u32 report_id,
                goto done_proc;
        }
 
-       remaining_bytes = do_div(buffer_size, sizeof(__s32));
+       remaining_bytes = buffer_size % sizeof(__s32);
+       buffer_size = buffer_size / sizeof(__s32);
        if (buffer_size) {
                for (i = 0; i < buffer_size; ++i) {
                        hid_set_field(report->field[field_index], i,
index 3147c8d09ea84a0a76d0fd7ead35931a89e29aed..e85bcae50f65f68c2035efcbb328006d1bf45bb7 100644 (file)
@@ -1864,16 +1864,24 @@ static int crypt_ctr(struct dm_target *ti, unsigned int argc, char **argv)
        }
 
        ret = -ENOMEM;
-       cc->io_queue = alloc_workqueue("kcryptd_io", WQ_MEM_RECLAIM, 1);
+       cc->io_queue = alloc_workqueue("kcryptd_io",
+                                      WQ_HIGHPRI |
+                                      WQ_MEM_RECLAIM,
+                                      1);
        if (!cc->io_queue) {
                ti->error = "Couldn't create kcryptd io queue";
                goto bad;
        }
 
        if (test_bit(DM_CRYPT_SAME_CPU, &cc->flags))
-               cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM, 1);
+               cc->crypt_queue = alloc_workqueue("kcryptd",
+                                                 WQ_HIGHPRI |
+                                                 WQ_MEM_RECLAIM, 1);
        else
-               cc->crypt_queue = alloc_workqueue("kcryptd", WQ_CPU_INTENSIVE | WQ_MEM_RECLAIM | WQ_UNBOUND,
+               cc->crypt_queue = alloc_workqueue("kcryptd",
+                                                 WQ_HIGHPRI |
+                                                 WQ_MEM_RECLAIM |
+                                                 WQ_UNBOUND,
                                                  num_online_cpus());
        if (!cc->crypt_queue) {
                ti->error = "Couldn't create kcryptd queue";
index 8b8c9a22360be35d51890f8fcab34e2cee9443a3..185c69c9738aa9cd8cf762a575d80fba4e08b5ba 100644 (file)
@@ -13,7 +13,7 @@
  *
  */
 
-#include <asm/atomic.h>
+#include <linux/atomic.h>
 
 #include <linux/err.h>
 #include <linux/init.h>
index 7befdaee555a67bc3b01d5a48cc0f397d2e0ce0a..9fef7f04c4e6da764c9e640d534bb9c61e8aa377 100644 (file)
@@ -593,6 +593,14 @@ static int mmc_blk_ioctl_cmd(struct block_device *bdev,
        struct mmc_card *card;
        int err = 0, ioc_err = 0;
 
+       /*
+        * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+        * whole block device, not on a partition.  This prevents overspray
+        * between sibling partitions.
+        */
+       if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+               return -EPERM;
+
        idata = mmc_blk_ioctl_copy_from_user(ic_ptr);
        if (IS_ERR(idata))
                return PTR_ERR(idata);
@@ -635,6 +643,14 @@ static int mmc_blk_ioctl_multi_cmd(struct block_device *bdev,
        int i, err = 0, ioc_err = 0;
        __u64 num_of_cmds;
 
+       /*
+        * The caller must have CAP_SYS_RAWIO, and must be calling this on the
+        * whole block device, not on a partition.  This prevents overspray
+        * between sibling partitions.
+        */
+       if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
+               return -EPERM;
+
        if (copy_from_user(&num_of_cmds, &user->num_of_cmds,
                           sizeof(num_of_cmds)))
                return -EFAULT;
@@ -690,14 +706,6 @@ cmd_err:
 static int mmc_blk_ioctl(struct block_device *bdev, fmode_t mode,
        unsigned int cmd, unsigned long arg)
 {
-       /*
-        * The caller must have CAP_SYS_RAWIO, and must be calling this on the
-        * whole block device, not on a partition.  This prevents overspray
-        * between sibling partitions.
-        */
-       if ((!capable(CAP_SYS_RAWIO)) || (bdev != bdev->bd_contains))
-               return -EPERM;
-
        switch (cmd) {
        case MMC_IOC_CMD:
                return mmc_blk_ioctl_cmd(bdev,
index 1be93a7ca4a1a35e79ffdda130079b4a8e1e974b..c621235601439b1cf220cb98bb59fe4830d9b812 100644 (file)
@@ -404,12 +404,19 @@ static void acc_hid_close(struct hid_device *hid)
 {
 }
 
+static int acc_hid_raw_request(struct hid_device *hid, unsigned char reportnum,
+       __u8 *buf, size_t len, unsigned char rtype, int reqtype)
+{
+       return 0;
+}
+
 static struct hid_ll_driver acc_hid_ll_driver = {
        .parse = acc_hid_parse,
        .start = acc_hid_start,
        .stop = acc_hid_stop,
        .open = acc_hid_open,
        .close = acc_hid_close,
+       .raw_request = acc_hid_raw_request,
 };
 
 static struct acc_hid_dev *acc_hid_new(struct acc_dev *dev,
index 39645be93502f5b2fa464581853b0cb586e00ca8..bcd817439dbf92efdc24885629a16a3de07bd261 100644 (file)
@@ -583,6 +583,11 @@ static void audio_disable(struct usb_function *f)
        usb_ep_disable(audio->in_ep);
 }
 
+static void audio_free_func(struct usb_function *f)
+{
+       /* no-op */
+}
+
 /*-------------------------------------------------------------------------*/
 
 static void audio_build_desc(struct audio_dev *audio)
@@ -827,6 +832,7 @@ static struct audio_dev _audio_dev = {
                .set_alt = audio_set_alt,
                .setup = audio_setup,
                .disable = audio_disable,
+               .free_func = audio_free_func,
        },
        .lock = __SPIN_LOCK_UNLOCKED(_audio_dev.lock),
        .idle_reqs = LIST_HEAD_INIT(_audio_dev.idle_reqs),
index 8f80a7e91314d705b6265a8c7080289707695cf3..74195be9b054ae4f547fd526615a9ba8d917677c 100644 (file)
@@ -135,6 +135,34 @@ static struct usb_interface_descriptor ptp_interface_desc = {
        .bInterfaceProtocol     = 1,
 };
 
+static struct usb_endpoint_descriptor mtp_ss_in_desc = {
+       .bLength                = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType        = USB_DT_ENDPOINT,
+       .bEndpointAddress       = USB_DIR_IN,
+       .bmAttributes           = USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor mtp_ss_in_comp_desc = {
+       .bLength                = sizeof(mtp_ss_in_comp_desc),
+       .bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
+       /* .bMaxBurst           = DYNAMIC, */
+};
+
+static struct usb_endpoint_descriptor mtp_ss_out_desc = {
+       .bLength                = USB_DT_ENDPOINT_SIZE,
+       .bDescriptorType        = USB_DT_ENDPOINT,
+       .bEndpointAddress       = USB_DIR_OUT,
+       .bmAttributes           = USB_ENDPOINT_XFER_BULK,
+       .wMaxPacketSize         = __constant_cpu_to_le16(1024),
+};
+
+static struct usb_ss_ep_comp_descriptor mtp_ss_out_comp_desc = {
+       .bLength                = sizeof(mtp_ss_out_comp_desc),
+       .bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
+       /* .bMaxBurst           = DYNAMIC, */
+};
+
 static struct usb_endpoint_descriptor mtp_highspeed_in_desc = {
        .bLength                = USB_DT_ENDPOINT_SIZE,
        .bDescriptorType        = USB_DT_ENDPOINT,
@@ -174,6 +202,12 @@ static struct usb_endpoint_descriptor mtp_intr_desc = {
        .bInterval              = 6,
 };
 
+static struct usb_ss_ep_comp_descriptor mtp_intr_ss_comp_desc = {
+       .bLength                = sizeof(mtp_intr_ss_comp_desc),
+       .bDescriptorType        = USB_DT_SS_ENDPOINT_COMP,
+       .wBytesPerInterval      = cpu_to_le16(INTR_BUFFER_SIZE),
+};
+
 static struct usb_descriptor_header *fs_mtp_descs[] = {
        (struct usb_descriptor_header *) &mtp_interface_desc,
        (struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
@@ -190,6 +224,17 @@ static struct usb_descriptor_header *hs_mtp_descs[] = {
        NULL,
 };
 
+static struct usb_descriptor_header *ss_mtp_descs[] = {
+       (struct usb_descriptor_header *) &mtp_interface_desc,
+       (struct usb_descriptor_header *) &mtp_ss_in_desc,
+       (struct usb_descriptor_header *) &mtp_ss_in_comp_desc,
+       (struct usb_descriptor_header *) &mtp_ss_out_desc,
+       (struct usb_descriptor_header *) &mtp_ss_out_comp_desc,
+       (struct usb_descriptor_header *) &mtp_intr_desc,
+       (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc,
+       NULL,
+};
+
 static struct usb_descriptor_header *fs_ptp_descs[] = {
        (struct usb_descriptor_header *) &ptp_interface_desc,
        (struct usb_descriptor_header *) &mtp_fullspeed_in_desc,
@@ -206,6 +251,17 @@ static struct usb_descriptor_header *hs_ptp_descs[] = {
        NULL,
 };
 
+static struct usb_descriptor_header *ss_ptp_descs[] = {
+       (struct usb_descriptor_header *) &ptp_interface_desc,
+       (struct usb_descriptor_header *) &mtp_ss_in_desc,
+       (struct usb_descriptor_header *) &mtp_ss_in_comp_desc,
+       (struct usb_descriptor_header *) &mtp_ss_out_desc,
+       (struct usb_descriptor_header *) &mtp_ss_out_comp_desc,
+       (struct usb_descriptor_header *) &mtp_intr_desc,
+       (struct usb_descriptor_header *) &mtp_intr_ss_comp_desc,
+       NULL,
+};
+
 static struct usb_string mtp_string_defs[] = {
        /* Naming interface "MTP" so libmtp will recognize us */
        [INTERFACE_STRING_INDEX].s      = "MTP",
@@ -290,6 +346,8 @@ struct mtp_instance {
        struct usb_function_instance func_inst;
        const char *name;
        struct mtp_dev *dev;
+       char mtp_ext_compat_id[16];
+       struct usb_os_desc mtp_os_desc;
 };
 
 /* temporary variable used between mtp_open() and mtp_gadget_bind() */
@@ -1101,6 +1159,7 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
        struct mtp_dev  *dev = func_to_mtp(f);
        int                     id;
        int                     ret;
+       struct mtp_instance *fi_mtp;
 
        dev->cdev = cdev;
        DBG(cdev, "mtp_function_bind dev: %p\n", dev);
@@ -1118,6 +1177,18 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
                mtp_string_defs[INTERFACE_STRING_INDEX].id = ret;
                mtp_interface_desc.iInterface = ret;
        }
+
+       fi_mtp = container_of(f->fi, struct mtp_instance, func_inst);
+
+       if (cdev->use_os_string) {
+               f->os_desc_table = kzalloc(sizeof(*f->os_desc_table),
+                                       GFP_KERNEL);
+               if (!f->os_desc_table)
+                       return -ENOMEM;
+               f->os_desc_n = 1;
+               f->os_desc_table[0].os_desc = &fi_mtp->mtp_os_desc;
+       }
+
        /* allocate endpoints */
        ret = mtp_create_bulk_endpoints(dev, &mtp_fullspeed_in_desc,
                        &mtp_fullspeed_out_desc, &mtp_intr_desc);
@@ -1131,10 +1202,24 @@ mtp_function_bind(struct usb_configuration *c, struct usb_function *f)
                mtp_highspeed_out_desc.bEndpointAddress =
                        mtp_fullspeed_out_desc.bEndpointAddress;
        }
+       /* support super speed hardware */
+       if (gadget_is_superspeed(c->cdev->gadget)) {
+               unsigned max_burst;
+
+               /* Calculate bMaxBurst, we know packet size is 1024 */
+               max_burst = min_t(unsigned, MTP_BULK_BUFFER_SIZE / 1024, 15);
+               mtp_ss_in_desc.bEndpointAddress =
+                       mtp_fullspeed_in_desc.bEndpointAddress;
+               mtp_ss_in_comp_desc.bMaxBurst = max_burst;
+               mtp_ss_out_desc.bEndpointAddress =
+                       mtp_fullspeed_out_desc.bEndpointAddress;
+               mtp_ss_out_comp_desc.bMaxBurst = max_burst;
+       }
 
        DBG(cdev, "%s speed %s: IN/%s, OUT/%s\n",
-                       gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full",
-                       f->name, dev->ep_in->name, dev->ep_out->name);
+               gadget_is_superspeed(c->cdev->gadget) ? "super" :
+               (gadget_is_dualspeed(c->cdev->gadget) ? "dual" : "full"),
+               f->name, dev->ep_in->name, dev->ep_out->name);
        return 0;
 }
 
@@ -1153,6 +1238,8 @@ mtp_function_unbind(struct usb_configuration *c, struct usb_function *f)
        while ((req = mtp_req_get(dev, &dev->intr_idle)))
                mtp_request_free(req, dev->ep_intr);
        dev->state = STATE_OFFLINE;
+       kfree(f->os_desc_table);
+       f->os_desc_n = 0;
 }
 
 static int mtp_function_set_alt(struct usb_function *f,
@@ -1336,6 +1423,7 @@ static void mtp_free_inst(struct usb_function_instance *fi)
        fi_mtp = to_fi_mtp(fi);
        kfree(fi_mtp->name);
        mtp_cleanup();
+       kfree(fi_mtp->mtp_os_desc.group.default_groups);
        kfree(fi_mtp);
 }
 
@@ -1343,6 +1431,8 @@ struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config)
 {
        struct mtp_instance *fi_mtp;
        int ret = 0;
+       struct usb_os_desc *descs[1];
+       char *names[1];
 
        fi_mtp = kzalloc(sizeof(*fi_mtp), GFP_KERNEL);
        if (!fi_mtp)
@@ -1350,6 +1440,13 @@ struct usb_function_instance *alloc_inst_mtp_ptp(bool mtp_config)
        fi_mtp->func_inst.set_inst_name = mtp_set_inst_name;
        fi_mtp->func_inst.free_func_inst = mtp_free_inst;
 
+       fi_mtp->mtp_os_desc.ext_compat_id = fi_mtp->mtp_ext_compat_id;
+       INIT_LIST_HEAD(&fi_mtp->mtp_os_desc.ext_prop);
+       descs[0] = &fi_mtp->mtp_os_desc;
+       names[0] = "MTP";
+       usb_os_desc_prepare_interf_dir(&fi_mtp->func_inst.group, 1,
+                                       descs, names, THIS_MODULE);
+
        if (mtp_config) {
                ret = mtp_setup_configfs(fi_mtp);
                if (ret) {
@@ -1410,9 +1507,11 @@ struct usb_function *function_alloc_mtp_ptp(struct usb_function_instance *fi,
        if (mtp_config) {
                dev->function.fs_descriptors = fs_mtp_descs;
                dev->function.hs_descriptors = hs_mtp_descs;
+               dev->function.ss_descriptors = ss_mtp_descs;
        } else {
                dev->function.fs_descriptors = fs_ptp_descs;
                dev->function.hs_descriptors = hs_ptp_descs;
+               dev->function.ss_descriptors = ss_ptp_descs;
        }
        dev->function.bind = mtp_function_bind;
        dev->function.unbind = mtp_function_unbind;
index 76b25445c6adfbedc19c50adf60d8b1d0c0e0afb..dd73dfe5dcabc65ac8c5c4061bf56da4a6c5eae5 100644 (file)
@@ -1014,6 +1014,7 @@ struct net_device *gether_setup_name_default(const char *netname)
        spin_lock_init(&dev->lock);
        spin_lock_init(&dev->req_lock);
        INIT_WORK(&dev->work, eth_work);
+       INIT_WORK(&dev->rx_work, process_rx_w);
        INIT_LIST_HEAD(&dev->tx_reqs);
        INIT_LIST_HEAD(&dev->rx_reqs);
 
index 33858b73d8bb99e64af9a1040e47e1ad5ddead34..2777db48fae0e91276b97616e94f564d93182fda 100644 (file)
@@ -11,4 +11,4 @@ menuconfig ADF_FBDEV
 menuconfig ADF_MEMBLOCK
        depends on ADF
        depends on HAVE_MEMBLOCK
-       tristate "Helper for using memblocks as buffers in ADF drivers"
+       bool "Helper for using memblocks as buffers in ADF drivers"
index 6ce72d8d1ee12473bfcb1e550967be2a0a1c8d27..a5d2dc39ba07589b58d38522bf79ba46ba0f9eed 100644 (file)
@@ -199,6 +199,7 @@ if MISC_FILESYSTEMS
 source "fs/adfs/Kconfig"
 source "fs/affs/Kconfig"
 source "fs/ecryptfs/Kconfig"
+source "fs/sdcardfs/Kconfig"
 source "fs/hfs/Kconfig"
 source "fs/hfsplus/Kconfig"
 source "fs/befs/Kconfig"
index 79f522575cba3e79e6909ca4c1c055d2cb54ce9a..3b54070cd6293e723c32cb184f20f39c1de6b2d8 100644 (file)
@@ -3,7 +3,7 @@
 #
 # 14 Sep 2000, Christoph Hellwig <hch@infradead.org>
 # Rewritten to use lists instead of if-statements.
-# 
+#
 
 obj-y :=       open.o read_write.o file_table.o super.o \
                char_dev.o stat.o exec.o pipe.o namei.o fcntl.o \
@@ -59,7 +59,7 @@ obj-y                         += devpts/
 
 obj-$(CONFIG_PROFILING)                += dcookies.o
 obj-$(CONFIG_DLM)              += dlm/
+
 # Do not add any filesystems before this line
 obj-$(CONFIG_FSCACHE)          += fscache/
 obj-$(CONFIG_REISERFS_FS)      += reiserfs/
@@ -81,6 +81,7 @@ obj-$(CONFIG_ISO9660_FS)      += isofs/
 obj-$(CONFIG_HFSPLUS_FS)       += hfsplus/ # Before hfs to find wrapped HFS+
 obj-$(CONFIG_HFS_FS)           += hfs/
 obj-$(CONFIG_ECRYPT_FS)                += ecryptfs/
+obj-$(CONFIG_SDCARD_FS)                += sdcardfs/
 obj-$(CONFIG_VXFS_FS)          += freevxfs/
 obj-$(CONFIG_NFS_FS)           += nfs/
 obj-$(CONFIG_EXPORTFS)         += exportfs/
index 3a93755e880fee23fa6d8370916caefb21f2c9eb..0c52941dd62c0d8ccb6d16b41472d9d6ad28fe5f 100644 (file)
@@ -651,7 +651,7 @@ static unsigned long randomize_stack_top(unsigned long stack_top)
 
        if ((current->flags & PF_RANDOMIZE) &&
                !(current->personality & ADDR_NO_RANDOMIZE)) {
-               random_variable = (unsigned long) get_random_int();
+               random_variable = get_random_long();
                random_variable &= STACK_RND_MASK;
                random_variable <<= PAGE_SHIFT;
        }
index 877bcbbd03ff549a8536bf289dac294f659645b9..24190e8b78604e02b4b512c5b52722c65b36e189 100644 (file)
@@ -3017,6 +3017,7 @@ char *d_absolute_path(const struct path *path,
                return ERR_PTR(error);
        return res;
 }
+EXPORT_SYMBOL(d_absolute_path);
 
 /*
  * same as __d_path but appends "(deleted)" for unlinked files.
index b8d08d0d0a4dbe061b9336dd7f861d32e13c8618..f72f3b25b3f22b92ab470d3711c008f3e8a425b1 100644 (file)
@@ -702,6 +702,8 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
        struct fsnotify_group *group;
        struct inode *inode;
        struct path path;
+       struct path alteredpath;
+       struct path *canonical_path = &path;
        struct fd f;
        int ret;
        unsigned flags = 0;
@@ -741,13 +743,22 @@ SYSCALL_DEFINE3(inotify_add_watch, int, fd, const char __user *, pathname,
        if (ret)
                goto fput_and_out;
 
+       /* support stacked filesystems */
+       if(path.dentry && path.dentry->d_op) {
+               if (path.dentry->d_op->d_canonical_path) {
+                       path.dentry->d_op->d_canonical_path(path.dentry, &alteredpath);
+                       canonical_path = &alteredpath;
+                       path_put(&path);
+               }
+       }
+
        /* inode held in place by reference to path; group by fget on fd */
-       inode = path.dentry->d_inode;
+       inode = canonical_path->dentry->d_inode;
        group = f.file->private_data;
 
        /* create/update an inode mark */
        ret = inotify_update_watch(group, inode, mask);
-       path_put(&path);
+       path_put(canonical_path);
 fput_and_out:
        fdput(f);
        return ret;
index 2429c804cf783afdeb4ce19d8a502cb427b85a8c..414041342a998d659c621320e86daa6dc3d57f32 100644 (file)
@@ -554,7 +554,7 @@ static int ramoops_parse_dt(struct platform_device *pdev,
 static int ramoops_probe(struct platform_device *pdev)
 {
        struct device *dev = &pdev->dev;
-       struct ramoops_platform_data *pdata = platform_get_drvdata(pdev);
+       struct ramoops_platform_data *pdata = pdev->dev.platform_data;
        struct ramoops_context *cxt = &oops_cxt;
        size_t dump_mem_sz;
        phys_addr_t paddr;
@@ -666,7 +666,6 @@ static int ramoops_probe(struct platform_device *pdev)
                cxt->size, (unsigned long long)cxt->phys_addr,
                cxt->ecc_info.ecc_size, cxt->ecc_info.block_size);
 
-       platform_set_drvdata(pdev, pdata);
        return 0;
 
 fail_buf:
diff --git a/fs/sdcardfs/Kconfig b/fs/sdcardfs/Kconfig
new file mode 100644 (file)
index 0000000..a1c1033
--- /dev/null
@@ -0,0 +1,13 @@
+config SDCARD_FS
+       tristate "sdcard file system"
+       depends on CONFIGFS_FS
+       default n
+       help
+         Sdcardfs is based on Wrapfs file system.
+
+config SDCARD_FS_FADV_NOACTIVE
+       bool "sdcardfs fadvise noactive support"
+       depends on FADV_NOACTIVE
+       default y
+       help
+         Sdcardfs supports fadvise noactive mode.
diff --git a/fs/sdcardfs/Makefile b/fs/sdcardfs/Makefile
new file mode 100644 (file)
index 0000000..b84fbb2
--- /dev/null
@@ -0,0 +1,7 @@
+SDCARDFS_VERSION="0.1"
+
+EXTRA_CFLAGS += -DSDCARDFS_VERSION=\"$(SDCARDFS_VERSION)\"
+
+obj-$(CONFIG_SDCARD_FS) += sdcardfs.o
+
+sdcardfs-y := dentry.o file.o inode.o main.o super.o lookup.o mmap.o packagelist.o derived_perm.o
diff --git a/fs/sdcardfs/dentry.c b/fs/sdcardfs/dentry.c
new file mode 100644 (file)
index 0000000..ba165ef
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * fs/sdcardfs/dentry.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+#include "linux/ctype.h"
+
+/*
+ * returns: -ERRNO if error (returned to user)
+ *          0: tell VFS to invalidate dentry
+ *          1: dentry is valid
+ */
+static int sdcardfs_d_revalidate(struct dentry *dentry, unsigned int flags)
+{
+       int err = 1;
+       struct path parent_lower_path, lower_path;
+       struct dentry *parent_dentry = NULL;
+       struct dentry *parent_lower_dentry = NULL;
+       struct dentry *lower_cur_parent_dentry = NULL;
+       struct dentry *lower_dentry = NULL;
+
+       if (flags & LOOKUP_RCU)
+               return -ECHILD;
+
+       spin_lock(&dentry->d_lock);
+       if (IS_ROOT(dentry)) {
+               spin_unlock(&dentry->d_lock);
+               return 1;
+       }
+       spin_unlock(&dentry->d_lock);
+
+       /* check uninitialized obb_dentry and
+        * whether the base obbpath has been changed or not */
+       if (is_obbpath_invalid(dentry)) {
+               d_drop(dentry);
+               return 0;
+       }
+
+       parent_dentry = dget_parent(dentry);
+       sdcardfs_get_lower_path(parent_dentry, &parent_lower_path);
+       sdcardfs_get_real_lower(dentry, &lower_path);
+       parent_lower_dentry = parent_lower_path.dentry;
+       lower_dentry = lower_path.dentry;
+       lower_cur_parent_dentry = dget_parent(lower_dentry);
+
+       spin_lock(&lower_dentry->d_lock);
+       if (d_unhashed(lower_dentry)) {
+               spin_unlock(&lower_dentry->d_lock);
+               d_drop(dentry);
+               err = 0;
+               goto out;
+       }
+       spin_unlock(&lower_dentry->d_lock);
+
+       if (parent_lower_dentry != lower_cur_parent_dentry) {
+               d_drop(dentry);
+               err = 0;
+               goto out;
+       }
+
+       if (dentry < lower_dentry) {
+               spin_lock(&dentry->d_lock);
+               spin_lock(&lower_dentry->d_lock);
+       } else {
+               spin_lock(&lower_dentry->d_lock);
+               spin_lock(&dentry->d_lock);
+       }
+
+       if (dentry->d_name.len != lower_dentry->d_name.len) {
+               __d_drop(dentry);
+               err = 0;
+       } else if (strncasecmp(dentry->d_name.name, lower_dentry->d_name.name,
+                               dentry->d_name.len) != 0) {
+               __d_drop(dentry);
+               err = 0;
+       }
+
+       if (dentry < lower_dentry) {
+               spin_unlock(&lower_dentry->d_lock);
+               spin_unlock(&dentry->d_lock);
+       } else {
+               spin_unlock(&dentry->d_lock);
+               spin_unlock(&lower_dentry->d_lock);
+       }
+
+out:
+       dput(parent_dentry);
+       dput(lower_cur_parent_dentry);
+       sdcardfs_put_lower_path(parent_dentry, &parent_lower_path);
+       sdcardfs_put_real_lower(dentry, &lower_path);
+       return err;
+}
+
+static void sdcardfs_d_release(struct dentry *dentry)
+{
+       /* release and reset the lower paths */
+       if(has_graft_path(dentry)) {
+               sdcardfs_put_reset_orig_path(dentry);
+       }
+       sdcardfs_put_reset_lower_path(dentry);
+       free_dentry_private_data(dentry);
+       return;
+}
+
+static int sdcardfs_hash_ci(const struct dentry *dentry,
+                               struct qstr *qstr)
+{
+       /*
+        * This function is copy of vfat_hashi.
+        * FIXME Should we support national language?
+        *       Refer to vfat_hashi()
+        * struct nls_table *t = MSDOS_SB(dentry->d_sb)->nls_io;
+        */
+       const unsigned char *name;
+       unsigned int len;
+       unsigned long hash;
+
+       name = qstr->name;
+       //len = vfat_striptail_len(qstr);
+       len = qstr->len;
+
+       hash = init_name_hash();
+       while (len--)
+               //hash = partial_name_hash(nls_tolower(t, *name++), hash);
+               hash = partial_name_hash(tolower(*name++), hash);
+       qstr->hash = end_name_hash(hash);
+
+       return 0;
+}
+
+/*
+ * Case insensitive compare of two vfat names.
+ */
+static int sdcardfs_cmp_ci(const struct dentry *parent,
+               const struct dentry *dentry,
+               unsigned int len, const char *str, const struct qstr *name)
+{
+       /* This function is copy of vfat_cmpi */
+       // FIXME Should we support national language?
+       //struct nls_table *t = MSDOS_SB(parent->d_sb)->nls_io;
+       //unsigned int alen, blen;
+
+       /* A filename cannot end in '.' or we treat it like it has none */
+       /*
+       alen = vfat_striptail_len(name);
+       blen = __vfat_striptail_len(len, str);
+       if (alen == blen) {
+               if (nls_strnicmp(t, name->name, str, alen) == 0)
+                       return 0;
+       }
+       */
+       if (name->len == len) {
+               if (strncasecmp(name->name, str, len) == 0)
+                       return 0;
+       }
+       return 1;
+}
+
+const struct dentry_operations sdcardfs_ci_dops = {
+       .d_revalidate   = sdcardfs_d_revalidate,
+       .d_release      = sdcardfs_d_release,
+       .d_hash         = sdcardfs_hash_ci,
+       .d_compare      = sdcardfs_cmp_ci,
+       .d_canonical_path = sdcardfs_get_real_lower,
+};
+
diff --git a/fs/sdcardfs/derived_perm.c b/fs/sdcardfs/derived_perm.c
new file mode 100644 (file)
index 0000000..128b3e5
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * fs/sdcardfs/derived_perm.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+
+/* copy derived state from parent inode */
+static void inherit_derived_state(struct inode *parent, struct inode *child)
+{
+       struct sdcardfs_inode_info *pi = SDCARDFS_I(parent);
+       struct sdcardfs_inode_info *ci = SDCARDFS_I(child);
+
+       ci->perm = PERM_INHERIT;
+       ci->userid = pi->userid;
+       ci->d_uid = pi->d_uid;
+       ci->under_android = pi->under_android;
+}
+
+/* helper function for derived state */
+void setup_derived_state(struct inode *inode, perm_t perm,
+                        userid_t userid, uid_t uid, bool under_android)
+{
+       struct sdcardfs_inode_info *info = SDCARDFS_I(inode);
+
+       info->perm = perm;
+       info->userid = userid;
+       info->d_uid = uid;
+       info->under_android = under_android;
+}
+
+/* While renaming, there is a point where we want the path from dentry, but the name from newdentry */
+void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry)
+{
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+       struct sdcardfs_inode_info *info = SDCARDFS_I(dentry->d_inode);
+       struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode);
+       appid_t appid;
+
+       /* By default, each inode inherits from its parent.
+        * the properties are maintained on its private fields
+        * because the inode attributes will be modified with that of
+        * its lower inode.
+        * The derived state will be updated on the last
+        * stage of each system call by fix_derived_permission(inode).
+        */
+
+       inherit_derived_state(parent->d_inode, dentry->d_inode);
+
+       /* Derive custom permissions based on parent and current node */
+       switch (parent_info->perm) {
+               case PERM_INHERIT:
+                       /* Already inherited above */
+                       break;
+               case PERM_PRE_ROOT:
+                       /* Legacy internal layout places users at top level */
+                       info->perm = PERM_ROOT;
+                       info->userid = simple_strtoul(newdentry->d_name.name, NULL, 10);
+                       break;
+               case PERM_ROOT:
+                       /* Assume masked off by default. */
+                       if (!strcasecmp(newdentry->d_name.name, "Android")) {
+                               /* App-specific directories inside; let anyone traverse */
+                               info->perm = PERM_ANDROID;
+                               info->under_android = true;
+                       }
+                       break;
+               case PERM_ANDROID:
+                       if (!strcasecmp(newdentry->d_name.name, "data")) {
+                               /* App-specific directories inside; let anyone traverse */
+                               info->perm = PERM_ANDROID_DATA;
+                       } else if (!strcasecmp(newdentry->d_name.name, "obb")) {
+                               /* App-specific directories inside; let anyone traverse */
+                               info->perm = PERM_ANDROID_OBB;
+                               /* Single OBB directory is always shared */
+                       } else if (!strcasecmp(newdentry->d_name.name, "media")) {
+                               /* App-specific directories inside; let anyone traverse */
+                               info->perm = PERM_ANDROID_MEDIA;
+                       }
+                       break;
+               case PERM_ANDROID_DATA:
+               case PERM_ANDROID_OBB:
+               case PERM_ANDROID_MEDIA:
+                       appid = get_appid(sbi->pkgl_id, newdentry->d_name.name);
+                       if (appid != 0) {
+                               info->d_uid = multiuser_get_uid(parent_info->userid, appid);
+                       }
+                       break;
+       }
+}
+
+void get_derived_permission(struct dentry *parent, struct dentry *dentry)
+{
+       get_derived_permission_new(parent, dentry, dentry);
+}
+
+void get_derive_permissions_recursive(struct dentry *parent) {
+       struct dentry *dentry;
+       list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
+               if (dentry && dentry->d_inode) {
+                       mutex_lock(&dentry->d_inode->i_mutex);
+                       get_derived_permission(parent, dentry);
+                       fix_derived_permission(dentry->d_inode);
+                       get_derive_permissions_recursive(dentry);
+                       mutex_unlock(&dentry->d_inode->i_mutex);
+               }
+       }
+}
+
+/* main function for updating derived permission */
+inline void update_derived_permission_lock(struct dentry *dentry)
+{
+       struct dentry *parent;
+
+       if(!dentry || !dentry->d_inode) {
+               printk(KERN_ERR "sdcardfs: %s: invalid dentry\n", __func__);
+               return;
+       }
+       /* FIXME:
+        * 1. need to check whether the dentry is updated or not
+        * 2. remove the root dentry update
+        */
+       mutex_lock(&dentry->d_inode->i_mutex);
+       if(IS_ROOT(dentry)) {
+               //setup_default_pre_root_state(dentry->d_inode);
+       } else {
+               parent = dget_parent(dentry);
+               if(parent) {
+                       get_derived_permission(parent, dentry);
+                       dput(parent);
+               }
+       }
+       fix_derived_permission(dentry->d_inode);
+       mutex_unlock(&dentry->d_inode->i_mutex);
+}
+
+int need_graft_path(struct dentry *dentry)
+{
+       int ret = 0;
+       struct dentry *parent = dget_parent(dentry);
+       struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode);
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+
+       if(parent_info->perm == PERM_ANDROID &&
+                       !strcasecmp(dentry->d_name.name, "obb")) {
+
+               /* /Android/obb is the base obbpath of DERIVED_UNIFIED */
+               if(!(sbi->options.multiuser == false
+                               && parent_info->userid == 0)) {
+                       ret = 1;
+               }
+       }
+       dput(parent);
+       return ret;
+}
+
+int is_obbpath_invalid(struct dentry *dent)
+{
+       int ret = 0;
+       struct sdcardfs_dentry_info *di = SDCARDFS_D(dent);
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dent->d_sb);
+       char *path_buf, *obbpath_s;
+
+       /* check the base obbpath has been changed.
+        * this routine can check an uninitialized obb dentry as well.
+        * regarding the uninitialized obb, refer to the sdcardfs_mkdir() */
+       spin_lock(&di->lock);
+       if(di->orig_path.dentry) {
+               if(!di->lower_path.dentry) {
+                       ret = 1;
+               } else {
+                       path_get(&di->lower_path);
+                       //lower_parent = lock_parent(lower_path->dentry);
+
+                       path_buf = kmalloc(PATH_MAX, GFP_ATOMIC);
+                       if(!path_buf) {
+                               ret = 1;
+                               printk(KERN_ERR "sdcardfs: fail to allocate path_buf in %s.\n", __func__);
+                       } else {
+                               obbpath_s = d_path(&di->lower_path, path_buf, PATH_MAX);
+                               if (d_unhashed(di->lower_path.dentry) ||
+                                       strcasecmp(sbi->obbpath_s, obbpath_s)) {
+                                       ret = 1;
+                               }
+                               kfree(path_buf);
+                       }
+
+                       //unlock_dir(lower_parent);
+                       path_put(&di->lower_path);
+               }
+       }
+       spin_unlock(&di->lock);
+       return ret;
+}
+
+int is_base_obbpath(struct dentry *dentry)
+{
+       int ret = 0;
+       struct dentry *parent = dget_parent(dentry);
+       struct sdcardfs_inode_info *parent_info= SDCARDFS_I(parent->d_inode);
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+
+       spin_lock(&SDCARDFS_D(dentry)->lock);
+       if (sbi->options.multiuser) {
+               if(parent_info->perm == PERM_PRE_ROOT &&
+                               !strcasecmp(dentry->d_name.name, "obb")) {
+                       ret = 1;
+               }
+       } else  if (parent_info->perm == PERM_ANDROID &&
+                       !strcasecmp(dentry->d_name.name, "obb")) {
+               ret = 1;
+       }
+       spin_unlock(&SDCARDFS_D(dentry)->lock);
+       return ret;
+}
+
+/* The lower_path will be stored to the dentry's orig_path
+ * and the base obbpath will be copyed to the lower_path variable.
+ * if an error returned, there's no change in the lower_path
+ * returns: -ERRNO if error (0: no error) */
+int setup_obb_dentry(struct dentry *dentry, struct path *lower_path)
+{
+       int err = 0;
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+       struct path obbpath;
+
+       /* A local obb dentry must have its own orig_path to support rmdir
+        * and mkdir of itself. Usually, we expect that the sbi->obbpath
+        * is avaiable on this stage. */
+       sdcardfs_set_orig_path(dentry, lower_path);
+
+       err = kern_path(sbi->obbpath_s,
+                       LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &obbpath);
+
+       if(!err) {
+               /* the obbpath base has been found */
+               printk(KERN_INFO "sdcardfs: the sbi->obbpath is found\n");
+               pathcpy(lower_path, &obbpath);
+       } else {
+               /* if the sbi->obbpath is not available, we can optionally
+                * setup the lower_path with its orig_path.
+                * but, the current implementation just returns an error
+                * because the sdcard daemon also regards this case as
+                * a lookup fail. */
+               printk(KERN_INFO "sdcardfs: the sbi->obbpath is not available\n");
+       }
+       return err;
+}
+
+
diff --git a/fs/sdcardfs/file.c b/fs/sdcardfs/file.c
new file mode 100644 (file)
index 0000000..c249fa9
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * fs/sdcardfs/file.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE
+#include <linux/backing-dev.h>
+#endif
+
+static ssize_t sdcardfs_read(struct file *file, char __user *buf,
+                          size_t count, loff_t *ppos)
+{
+       int err;
+       struct file *lower_file;
+       struct dentry *dentry = file->f_path.dentry;
+#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE
+       struct backing_dev_info *bdi;
+#endif
+
+       lower_file = sdcardfs_lower_file(file);
+
+#ifdef CONFIG_SDCARD_FS_FADV_NOACTIVE
+       if (file->f_mode & FMODE_NOACTIVE) {
+               if (!(lower_file->f_mode & FMODE_NOACTIVE)) {
+                       bdi = lower_file->f_mapping->backing_dev_info;
+                       lower_file->f_ra.ra_pages = bdi->ra_pages * 2;
+                       spin_lock(&lower_file->f_lock);
+                       lower_file->f_mode |= FMODE_NOACTIVE;
+                       spin_unlock(&lower_file->f_lock);
+               }
+       }
+#endif
+
+       err = vfs_read(lower_file, buf, count, ppos);
+       /* update our inode atime upon a successful lower read */
+       if (err >= 0)
+               fsstack_copy_attr_atime(d_inode(dentry),
+                                       file_inode(lower_file));
+
+       return err;
+}
+
+static ssize_t sdcardfs_write(struct file *file, const char __user *buf,
+                           size_t count, loff_t *ppos)
+{
+       int err;
+       struct file *lower_file;
+       struct dentry *dentry = file->f_path.dentry;
+
+       /* check disk space */
+       if (!check_min_free_space(dentry, count, 0)) {
+               printk(KERN_INFO "No minimum free space.\n");
+               return -ENOSPC;
+       }
+
+       lower_file = sdcardfs_lower_file(file);
+       err = vfs_write(lower_file, buf, count, ppos);
+       /* update our inode times+sizes upon a successful lower write */
+       if (err >= 0) {
+               fsstack_copy_inode_size(d_inode(dentry),
+                                       file_inode(lower_file));
+               fsstack_copy_attr_times(d_inode(dentry),
+                                       file_inode(lower_file));
+       }
+
+       return err;
+}
+
+static int sdcardfs_readdir(struct file *file, struct dir_context *ctx)
+{
+       int err;
+       struct file *lower_file = NULL;
+       struct dentry *dentry = file->f_path.dentry;
+
+       lower_file = sdcardfs_lower_file(file);
+
+       lower_file->f_pos = file->f_pos;
+       err = iterate_dir(lower_file, ctx);
+       file->f_pos = lower_file->f_pos;
+       if (err >= 0)           /* copy the atime */
+               fsstack_copy_attr_atime(d_inode(dentry),
+                                       file_inode(lower_file));
+       return err;
+}
+
+static long sdcardfs_unlocked_ioctl(struct file *file, unsigned int cmd,
+                                 unsigned long arg)
+{
+       long err = -ENOTTY;
+       struct file *lower_file;
+
+       lower_file = sdcardfs_lower_file(file);
+
+       /* XXX: use vfs_ioctl if/when VFS exports it */
+       if (!lower_file || !lower_file->f_op)
+               goto out;
+       if (lower_file->f_op->unlocked_ioctl)
+               err = lower_file->f_op->unlocked_ioctl(lower_file, cmd, arg);
+
+out:
+       return err;
+}
+
+#ifdef CONFIG_COMPAT
+static long sdcardfs_compat_ioctl(struct file *file, unsigned int cmd,
+                               unsigned long arg)
+{
+       long err = -ENOTTY;
+       struct file *lower_file;
+
+       lower_file = sdcardfs_lower_file(file);
+
+       /* XXX: use vfs_ioctl if/when VFS exports it */
+       if (!lower_file || !lower_file->f_op)
+               goto out;
+       if (lower_file->f_op->compat_ioctl)
+               err = lower_file->f_op->compat_ioctl(lower_file, cmd, arg);
+
+out:
+       return err;
+}
+#endif
+
+static int sdcardfs_mmap(struct file *file, struct vm_area_struct *vma)
+{
+       int err = 0;
+       bool willwrite;
+       struct file *lower_file;
+       const struct vm_operations_struct *saved_vm_ops = NULL;
+
+       /* this might be deferred to mmap's writepage */
+       willwrite = ((vma->vm_flags | VM_SHARED | VM_WRITE) == vma->vm_flags);
+
+       /*
+        * File systems which do not implement ->writepage may use
+        * generic_file_readonly_mmap as their ->mmap op.  If you call
+        * generic_file_readonly_mmap with VM_WRITE, you'd get an -EINVAL.
+        * But we cannot call the lower ->mmap op, so we can't tell that
+        * writeable mappings won't work.  Therefore, our only choice is to
+        * check if the lower file system supports the ->writepage, and if
+        * not, return EINVAL (the same error that
+        * generic_file_readonly_mmap returns in that case).
+        */
+       lower_file = sdcardfs_lower_file(file);
+       if (willwrite && !lower_file->f_mapping->a_ops->writepage) {
+               err = -EINVAL;
+               printk(KERN_ERR "sdcardfs: lower file system does not "
+                      "support writeable mmap\n");
+               goto out;
+       }
+
+       /*
+        * find and save lower vm_ops.
+        *
+        * XXX: the VFS should have a cleaner way of finding the lower vm_ops
+        */
+       if (!SDCARDFS_F(file)->lower_vm_ops) {
+               err = lower_file->f_op->mmap(lower_file, vma);
+               if (err) {
+                       printk(KERN_ERR "sdcardfs: lower mmap failed %d\n", err);
+                       goto out;
+               }
+               saved_vm_ops = vma->vm_ops; /* save: came from lower ->mmap */
+               err = do_munmap(current->mm, vma->vm_start,
+                               vma->vm_end - vma->vm_start);
+               if (err) {
+                       printk(KERN_ERR "sdcardfs: do_munmap failed %d\n", err);
+                       goto out;
+               }
+       }
+
+       /*
+        * Next 3 lines are all I need from generic_file_mmap.  I definitely
+        * don't want its test for ->readpage which returns -ENOEXEC.
+        */
+       file_accessed(file);
+       vma->vm_ops = &sdcardfs_vm_ops;
+
+       file->f_mapping->a_ops = &sdcardfs_aops; /* set our aops */
+       if (!SDCARDFS_F(file)->lower_vm_ops) /* save for our ->fault */
+               SDCARDFS_F(file)->lower_vm_ops = saved_vm_ops;
+
+out:
+       return err;
+}
+
+static int sdcardfs_open(struct inode *inode, struct file *file)
+{
+       int err = 0;
+       struct file *lower_file = NULL;
+       struct path lower_path;
+       struct dentry *dentry = file->f_path.dentry;
+       struct dentry *parent = dget_parent(dentry);
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+       const struct cred *saved_cred = NULL;
+
+       /* don't open unhashed/deleted files */
+       if (d_unhashed(dentry)) {
+               err = -ENOENT;
+               goto out_err;
+       }
+
+       if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                         "     dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               err = -EACCES;
+               goto out_err;
+       }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED(sbi, saved_cred);
+
+       file->private_data =
+               kzalloc(sizeof(struct sdcardfs_file_info), GFP_KERNEL);
+       if (!SDCARDFS_F(file)) {
+               err = -ENOMEM;
+               goto out_revert_cred;
+       }
+
+       /* open lower object and link sdcardfs's file struct to lower's */
+       sdcardfs_get_lower_path(file->f_path.dentry, &lower_path);
+       lower_file = dentry_open(&lower_path, file->f_flags, current_cred());
+       path_put(&lower_path);
+       if (IS_ERR(lower_file)) {
+               err = PTR_ERR(lower_file);
+               lower_file = sdcardfs_lower_file(file);
+               if (lower_file) {
+                       sdcardfs_set_lower_file(file, NULL);
+                       fput(lower_file); /* fput calls dput for lower_dentry */
+               }
+       } else {
+               sdcardfs_set_lower_file(file, lower_file);
+       }
+
+       if (err)
+               kfree(SDCARDFS_F(file));
+       else {
+               sdcardfs_copy_and_fix_attrs(inode, sdcardfs_lower_inode(inode));
+       }
+
+out_revert_cred:
+       REVERT_CRED(saved_cred);
+out_err:
+       dput(parent);
+       return err;
+}
+
+static int sdcardfs_flush(struct file *file, fl_owner_t id)
+{
+       int err = 0;
+       struct file *lower_file = NULL;
+
+       lower_file = sdcardfs_lower_file(file);
+       if (lower_file && lower_file->f_op && lower_file->f_op->flush) {
+               filemap_write_and_wait(file->f_mapping);
+               err = lower_file->f_op->flush(lower_file, id);
+       }
+
+       return err;
+}
+
+/* release all lower object references & free the file info structure */
+static int sdcardfs_file_release(struct inode *inode, struct file *file)
+{
+       struct file *lower_file;
+
+       lower_file = sdcardfs_lower_file(file);
+       if (lower_file) {
+               sdcardfs_set_lower_file(file, NULL);
+               fput(lower_file);
+       }
+
+       kfree(SDCARDFS_F(file));
+       return 0;
+}
+
+static int sdcardfs_fsync(struct file *file, loff_t start, loff_t end,
+                       int datasync)
+{
+       int err;
+       struct file *lower_file;
+       struct path lower_path;
+       struct dentry *dentry = file->f_path.dentry;
+
+       err = __generic_file_fsync(file, start, end, datasync);
+       if (err)
+               goto out;
+
+       lower_file = sdcardfs_lower_file(file);
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       err = vfs_fsync_range(lower_file, start, end, datasync);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+out:
+       return err;
+}
+
+static int sdcardfs_fasync(int fd, struct file *file, int flag)
+{
+       int err = 0;
+       struct file *lower_file = NULL;
+
+       lower_file = sdcardfs_lower_file(file);
+       if (lower_file->f_op && lower_file->f_op->fasync)
+               err = lower_file->f_op->fasync(fd, lower_file, flag);
+
+       return err;
+}
+
+const struct file_operations sdcardfs_main_fops = {
+       .llseek         = generic_file_llseek,
+       .read           = sdcardfs_read,
+       .write          = sdcardfs_write,
+       .unlocked_ioctl = sdcardfs_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = sdcardfs_compat_ioctl,
+#endif
+       .mmap           = sdcardfs_mmap,
+       .open           = sdcardfs_open,
+       .flush          = sdcardfs_flush,
+       .release        = sdcardfs_file_release,
+       .fsync          = sdcardfs_fsync,
+       .fasync         = sdcardfs_fasync,
+};
+
+/* trimmed directory options */
+const struct file_operations sdcardfs_dir_fops = {
+       .llseek         = generic_file_llseek,
+       .read           = generic_read_dir,
+       .iterate        = sdcardfs_readdir,
+       .unlocked_ioctl = sdcardfs_unlocked_ioctl,
+#ifdef CONFIG_COMPAT
+       .compat_ioctl   = sdcardfs_compat_ioctl,
+#endif
+       .open           = sdcardfs_open,
+       .release        = sdcardfs_file_release,
+       .flush          = sdcardfs_flush,
+       .fsync          = sdcardfs_fsync,
+       .fasync         = sdcardfs_fasync,
+};
diff --git a/fs/sdcardfs/inode.c b/fs/sdcardfs/inode.c
new file mode 100644 (file)
index 0000000..2528da0
--- /dev/null
@@ -0,0 +1,802 @@
+/*
+ * fs/sdcardfs/inode.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+
+/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
+const struct cred * override_fsids(struct sdcardfs_sb_info* sbi)
+{
+       struct cred * cred;
+       const struct cred * old_cred;
+
+       cred = prepare_creds();
+       if (!cred)
+               return NULL;
+
+       cred->fsuid = make_kuid(&init_user_ns, sbi->options.fs_low_uid);
+       cred->fsgid = make_kgid(&init_user_ns, sbi->options.fs_low_gid);
+
+       old_cred = override_creds(cred);
+
+       return old_cred;
+}
+
+/* Do not directly use this function, use REVERT_CRED() instead. */
+void revert_fsids(const struct cred * old_cred)
+{
+       const struct cred * cur_cred;
+
+       cur_cred = current->cred;
+       revert_creds(old_cred);
+       put_cred(cur_cred);
+}
+
+static int sdcardfs_create(struct inode *dir, struct dentry *dentry,
+                        umode_t mode, bool want_excl)
+{
+       int err;
+       struct dentry *lower_dentry;
+       struct dentry *lower_parent_dentry = NULL;
+       struct path lower_path;
+       const struct cred *saved_cred = NULL;
+
+       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                "  dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               err = -EACCES;
+               goto out_eacces;
+       }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+
+       /* set last 16bytes of mode field to 0664 */
+       mode = (mode & S_IFMT) | 00664;
+       err = vfs_create(d_inode(lower_parent_dentry), lower_dentry, mode, want_excl);
+       if (err)
+               goto out;
+
+       err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, SDCARDFS_I(dir)->userid);
+       if (err)
+               goto out;
+       fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
+       fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
+
+out:
+       unlock_dir(lower_parent_dentry);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+       REVERT_CRED(saved_cred);
+out_eacces:
+       return err;
+}
+
+#if 0
+static int sdcardfs_link(struct dentry *old_dentry, struct inode *dir,
+                      struct dentry *new_dentry)
+{
+       struct dentry *lower_old_dentry;
+       struct dentry *lower_new_dentry;
+       struct dentry *lower_dir_dentry;
+       u64 file_size_save;
+       int err;
+       struct path lower_old_path, lower_new_path;
+
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb));
+
+       file_size_save = i_size_read(d_inode(old_dentry));
+       sdcardfs_get_lower_path(old_dentry, &lower_old_path);
+       sdcardfs_get_lower_path(new_dentry, &lower_new_path);
+       lower_old_dentry = lower_old_path.dentry;
+       lower_new_dentry = lower_new_path.dentry;
+       lower_dir_dentry = lock_parent(lower_new_dentry);
+
+       err = vfs_link(lower_old_dentry, d_inode(lower_dir_dentry),
+                      lower_new_dentry, NULL);
+       if (err || !d_inode(lower_new_dentry))
+               goto out;
+
+       err = sdcardfs_interpose(new_dentry, dir->i_sb, &lower_new_path);
+       if (err)
+               goto out;
+       fsstack_copy_attr_times(dir, d_inode(lower_new_dentry));
+       fsstack_copy_inode_size(dir, d_inode(lower_new_dentry));
+       set_nlink(d_inode(old_dentry),
+                 sdcardfs_lower_inode(d_inode(old_dentry))->i_nlink);
+       i_size_write(d_inode(new_dentry), file_size_save);
+out:
+       unlock_dir(lower_dir_dentry);
+       sdcardfs_put_lower_path(old_dentry, &lower_old_path);
+       sdcardfs_put_lower_path(new_dentry, &lower_new_path);
+       REVERT_CRED();
+       return err;
+}
+#endif
+
+static int sdcardfs_unlink(struct inode *dir, struct dentry *dentry)
+{
+       int err;
+       struct dentry *lower_dentry;
+       struct inode *lower_dir_inode = sdcardfs_lower_inode(dir);
+       struct dentry *lower_dir_dentry;
+       struct path lower_path;
+       const struct cred *saved_cred = NULL;
+
+       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                "  dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               err = -EACCES;
+               goto out_eacces;
+       }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       dget(lower_dentry);
+       lower_dir_dentry = lock_parent(lower_dentry);
+
+       err = vfs_unlink(lower_dir_inode, lower_dentry, NULL);
+
+       /*
+        * Note: unlinking on top of NFS can cause silly-renamed files.
+        * Trying to delete such files results in EBUSY from NFS
+        * below.  Silly-renamed files will get deleted by NFS later on, so
+        * we just need to detect them here and treat such EBUSY errors as
+        * if the upper file was successfully deleted.
+        */
+       if (err == -EBUSY && lower_dentry->d_flags & DCACHE_NFSFS_RENAMED)
+               err = 0;
+       if (err)
+               goto out;
+       fsstack_copy_attr_times(dir, lower_dir_inode);
+       fsstack_copy_inode_size(dir, lower_dir_inode);
+       set_nlink(d_inode(dentry),
+                 sdcardfs_lower_inode(d_inode(dentry))->i_nlink);
+       d_inode(dentry)->i_ctime = dir->i_ctime;
+       d_drop(dentry); /* this is needed, else LTP fails (VFS won't do it) */
+out:
+       unlock_dir(lower_dir_dentry);
+       dput(lower_dentry);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+       REVERT_CRED(saved_cred);
+out_eacces:
+       return err;
+}
+
+#if 0
+static int sdcardfs_symlink(struct inode *dir, struct dentry *dentry,
+                         const char *symname)
+{
+       int err;
+       struct dentry *lower_dentry;
+       struct dentry *lower_parent_dentry = NULL;
+       struct path lower_path;
+
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb));
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+
+       err = vfs_symlink(d_inode(lower_parent_dentry), lower_dentry, symname);
+       if (err)
+               goto out;
+       err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path);
+       if (err)
+               goto out;
+       fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
+       fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
+
+out:
+       unlock_dir(lower_parent_dentry);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+       REVERT_CRED();
+       return err;
+}
+#endif
+
+static int touch(char *abs_path, mode_t mode) {
+       struct file *filp = filp_open(abs_path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW, mode);
+       if (IS_ERR(filp)) {
+               if (PTR_ERR(filp) == -EEXIST) {
+                       return 0;
+               }
+               else {
+                       printk(KERN_ERR "sdcardfs: failed to open(%s): %ld\n",
+                                               abs_path, PTR_ERR(filp));
+                       return PTR_ERR(filp);
+               }
+       }
+       filp_close(filp, current->files);
+       return 0;
+}
+
+static int sdcardfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
+{
+       int err;
+       int make_nomedia_in_obb = 0;
+       struct dentry *lower_dentry;
+       struct dentry *lower_parent_dentry = NULL;
+       struct path lower_path;
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+       const struct cred *saved_cred = NULL;
+       struct sdcardfs_inode_info *pi = SDCARDFS_I(dir);
+       char *page_buf;
+       char *nomedia_dir_name;
+       char *nomedia_fullpath;
+       int fullpath_namelen;
+       int touch_err = 0;
+
+       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                "  dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               err = -EACCES;
+               goto out_eacces;
+       }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+
+       /* check disk space */
+       if (!check_min_free_space(dentry, 0, 1)) {
+               printk(KERN_INFO "sdcardfs: No minimum free space.\n");
+               err = -ENOSPC;
+               goto out_revert;
+       }
+
+       /* the lower_dentry is negative here */
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+
+       /* set last 16bytes of mode field to 0775 */
+       mode = (mode & S_IFMT) | 00775;
+       err = vfs_mkdir(d_inode(lower_parent_dentry), lower_dentry, mode);
+
+       if (err)
+               goto out;
+
+       /* if it is a local obb dentry, setup it with the base obbpath */
+       if(need_graft_path(dentry)) {
+
+               err = setup_obb_dentry(dentry, &lower_path);
+               if(err) {
+                       /* if the sbi->obbpath is not available, the lower_path won't be
+                        * changed by setup_obb_dentry() but the lower path is saved to
+                        * its orig_path. this dentry will be revalidated later.
+                        * but now, the lower_path should be NULL */
+                       sdcardfs_put_reset_lower_path(dentry);
+
+                       /* the newly created lower path which saved to its orig_path or
+                        * the lower_path is the base obbpath.
+                        * therefore, an additional path_get is required */
+                       path_get(&lower_path);
+               } else
+                       make_nomedia_in_obb = 1;
+       }
+
+       err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path, pi->userid);
+       if (err)
+               goto out;
+
+       fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
+       fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
+       /* update number of links on parent directory */
+       set_nlink(dir, sdcardfs_lower_inode(dir)->i_nlink);
+
+       if ((!sbi->options.multiuser) && (!strcasecmp(dentry->d_name.name, "obb"))
+               && (pi->perm == PERM_ANDROID) && (pi->userid == 0))
+               make_nomedia_in_obb = 1;
+
+       /* When creating /Android/data and /Android/obb, mark them as .nomedia */
+       if (make_nomedia_in_obb ||
+               ((pi->perm == PERM_ANDROID) && (!strcasecmp(dentry->d_name.name, "data")))) {
+
+               page_buf = (char *)__get_free_page(GFP_KERNEL);
+               if (!page_buf) {
+                       printk(KERN_ERR "sdcardfs: failed to allocate page buf\n");
+                       goto out;
+               }
+
+               nomedia_dir_name = d_absolute_path(&lower_path, page_buf, PAGE_SIZE);
+               if (IS_ERR(nomedia_dir_name)) {
+                       free_page((unsigned long)page_buf);
+                       printk(KERN_ERR "sdcardfs: failed to get .nomedia dir name\n");
+                       goto out;
+               }
+
+               fullpath_namelen = page_buf + PAGE_SIZE - nomedia_dir_name - 1;
+               fullpath_namelen += strlen("/.nomedia");
+               nomedia_fullpath = kzalloc(fullpath_namelen + 1, GFP_KERNEL);
+               if (!nomedia_fullpath) {
+                       free_page((unsigned long)page_buf);
+                       printk(KERN_ERR "sdcardfs: failed to allocate .nomedia fullpath buf\n");
+                       goto out;
+               }
+
+               strcpy(nomedia_fullpath, nomedia_dir_name);
+               free_page((unsigned long)page_buf);
+               strcat(nomedia_fullpath, "/.nomedia");
+               touch_err = touch(nomedia_fullpath, 0664);
+               if (touch_err) {
+                       printk(KERN_ERR "sdcardfs: failed to touch(%s): %d\n",
+                                                       nomedia_fullpath, touch_err);
+                       kfree(nomedia_fullpath);
+                       goto out;
+               }
+               kfree(nomedia_fullpath);
+       }
+out:
+       unlock_dir(lower_parent_dentry);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+out_revert:
+       REVERT_CRED(saved_cred);
+out_eacces:
+       return err;
+}
+
+static int sdcardfs_rmdir(struct inode *dir, struct dentry *dentry)
+{
+       struct dentry *lower_dentry;
+       struct dentry *lower_dir_dentry;
+       int err;
+       struct path lower_path;
+       const struct cred *saved_cred = NULL;
+
+       if(!check_caller_access_to_name(dir, dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                "  dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               err = -EACCES;
+               goto out_eacces;
+       }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb), saved_cred);
+
+       /* sdcardfs_get_real_lower(): in case of remove an user's obb dentry
+        * the dentry on the original path should be deleted. */
+       sdcardfs_get_real_lower(dentry, &lower_path);
+
+       lower_dentry = lower_path.dentry;
+       lower_dir_dentry = lock_parent(lower_dentry);
+
+       err = vfs_rmdir(d_inode(lower_dir_dentry), lower_dentry);
+       if (err)
+               goto out;
+
+       d_drop(dentry); /* drop our dentry on success (why not VFS's job?) */
+       if (d_inode(dentry))
+               clear_nlink(d_inode(dentry));
+       fsstack_copy_attr_times(dir, d_inode(lower_dir_dentry));
+       fsstack_copy_inode_size(dir, d_inode(lower_dir_dentry));
+       set_nlink(dir, d_inode(lower_dir_dentry)->i_nlink);
+
+out:
+       unlock_dir(lower_dir_dentry);
+       sdcardfs_put_real_lower(dentry, &lower_path);
+       REVERT_CRED(saved_cred);
+out_eacces:
+       return err;
+}
+
+#if 0
+static int sdcardfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode,
+                       dev_t dev)
+{
+       int err;
+       struct dentry *lower_dentry;
+       struct dentry *lower_parent_dentry = NULL;
+       struct path lower_path;
+
+       OVERRIDE_CRED(SDCARDFS_SB(dir->i_sb));
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_parent_dentry = lock_parent(lower_dentry);
+
+       err = vfs_mknod(d_inode(lower_parent_dentry), lower_dentry, mode, dev);
+       if (err)
+               goto out;
+
+       err = sdcardfs_interpose(dentry, dir->i_sb, &lower_path);
+       if (err)
+               goto out;
+       fsstack_copy_attr_times(dir, sdcardfs_lower_inode(dir));
+       fsstack_copy_inode_size(dir, d_inode(lower_parent_dentry));
+
+out:
+       unlock_dir(lower_parent_dentry);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+       REVERT_CRED();
+       return err;
+}
+#endif
+
+/*
+ * The locking rules in sdcardfs_rename are complex.  We could use a simpler
+ * superblock-level name-space lock for renames and copy-ups.
+ */
+static int sdcardfs_rename(struct inode *old_dir, struct dentry *old_dentry,
+                        struct inode *new_dir, struct dentry *new_dentry)
+{
+       int err = 0;
+       struct dentry *lower_old_dentry = NULL;
+       struct dentry *lower_new_dentry = NULL;
+       struct dentry *lower_old_dir_dentry = NULL;
+       struct dentry *lower_new_dir_dentry = NULL;
+       struct dentry *trap = NULL;
+       struct dentry *new_parent = NULL;
+       struct path lower_old_path, lower_new_path;
+       const struct cred *saved_cred = NULL;
+
+       if(!check_caller_access_to_name(old_dir, old_dentry->d_name.name) ||
+               !check_caller_access_to_name(new_dir, new_dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                "  new_dentry: %s, task:%s\n",
+                                                __func__, new_dentry->d_name.name, current->comm);
+               err = -EACCES;
+               goto out_eacces;
+       }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED(SDCARDFS_SB(old_dir->i_sb), saved_cred);
+
+       sdcardfs_get_real_lower(old_dentry, &lower_old_path);
+       sdcardfs_get_lower_path(new_dentry, &lower_new_path);
+       lower_old_dentry = lower_old_path.dentry;
+       lower_new_dentry = lower_new_path.dentry;
+       lower_old_dir_dentry = dget_parent(lower_old_dentry);
+       lower_new_dir_dentry = dget_parent(lower_new_dentry);
+
+       trap = lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+       /* source should not be ancestor of target */
+       if (trap == lower_old_dentry) {
+               err = -EINVAL;
+               goto out;
+       }
+       /* target should not be ancestor of source */
+       if (trap == lower_new_dentry) {
+               err = -ENOTEMPTY;
+               goto out;
+       }
+
+       err = vfs_rename(d_inode(lower_old_dir_dentry), lower_old_dentry,
+                        d_inode(lower_new_dir_dentry), lower_new_dentry,
+                        NULL, 0);
+       if (err)
+               goto out;
+
+       /* Copy attrs from lower dir, but i_uid/i_gid */
+       sdcardfs_copy_and_fix_attrs(new_dir, d_inode(lower_new_dir_dentry));
+       fsstack_copy_inode_size(new_dir, d_inode(lower_new_dir_dentry));
+
+       if (new_dir != old_dir) {
+               sdcardfs_copy_and_fix_attrs(old_dir, d_inode(lower_old_dir_dentry));
+               fsstack_copy_inode_size(old_dir, d_inode(lower_old_dir_dentry));
+
+               /* update the derived permission of the old_dentry
+                * with its new parent
+                */
+               new_parent = dget_parent(new_dentry);
+               if(new_parent) {
+                       if(d_inode(old_dentry)) {
+                               update_derived_permission_lock(old_dentry);
+                       }
+                       dput(new_parent);
+               }
+       }
+       /* At this point, not all dentry information has been moved, so
+        * we pass along new_dentry for the name.*/
+       mutex_lock(&d_inode(old_dentry)->i_mutex);
+       get_derived_permission_new(new_dentry->d_parent, old_dentry, new_dentry);
+       fix_derived_permission(d_inode(old_dentry));
+       get_derive_permissions_recursive(old_dentry);
+       mutex_unlock(&d_inode(old_dentry)->i_mutex);
+out:
+       unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);
+       dput(lower_old_dir_dentry);
+       dput(lower_new_dir_dentry);
+       sdcardfs_put_real_lower(old_dentry, &lower_old_path);
+       sdcardfs_put_lower_path(new_dentry, &lower_new_path);
+       REVERT_CRED(saved_cred);
+out_eacces:
+       return err;
+}
+
+#if 0
+static int sdcardfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)
+{
+       int err;
+       struct dentry *lower_dentry;
+       struct path lower_path;
+       /* XXX readlink does not requires overriding credential */
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       if (!d_inode(lower_dentry)->i_op ||
+           !d_inode(lower_dentry)->i_op->readlink) {
+               err = -EINVAL;
+               goto out;
+       }
+
+       err = d_inode(lower_dentry)->i_op->readlink(lower_dentry,
+                                                   buf, bufsiz);
+       if (err < 0)
+               goto out;
+       fsstack_copy_attr_atime(d_inode(dentry), d_inode(lower_dentry));
+
+out:
+       sdcardfs_put_lower_path(dentry, &lower_path);
+       return err;
+}
+#endif
+
+#if 0
+static const char *sdcardfs_follow_link(struct dentry *dentry, void **cookie)
+{
+       char *buf;
+       int len = PAGE_SIZE, err;
+       mm_segment_t old_fs;
+
+       /* This is freed by the put_link method assuming a successful call. */
+       buf = kmalloc(len, GFP_KERNEL);
+       if (!buf) {
+               buf = ERR_PTR(-ENOMEM);
+               return buf;
+       }
+
+       /* read the symlink, and then we will follow it */
+       old_fs = get_fs();
+       set_fs(KERNEL_DS);
+       err = sdcardfs_readlink(dentry, buf, len);
+       set_fs(old_fs);
+       if (err < 0) {
+               kfree(buf);
+               buf = ERR_PTR(err);
+       } else {
+               buf[err] = '\0';
+       }
+       return *cookie = buf;
+}
+#endif
+
+static int sdcardfs_permission(struct inode *inode, int mask)
+{
+       int err;
+
+       /*
+        * Permission check on sdcardfs inode.
+        * Calling process should have AID_SDCARD_RW permission
+        */
+       err = generic_permission(inode, mask);
+
+       /* XXX
+        * Original sdcardfs code calls inode_permission(lower_inode,.. )
+        * for checking inode permission. But doing such things here seems
+        * duplicated work, because the functions called after this func,
+        * such as vfs_create, vfs_unlink, vfs_rename, and etc,
+        * does exactly same thing, i.e., they calls inode_permission().
+        * So we just let they do the things.
+        * If there are any security hole, just uncomment following if block.
+        */
+#if 0
+       if (!err) {
+               /*
+                * Permission check on lower_inode(=EXT4).
+                * we check it with AID_MEDIA_RW permission
+                */
+               struct inode *lower_inode;
+               OVERRIDE_CRED(SDCARDFS_SB(inode->sb));
+
+               lower_inode = sdcardfs_lower_inode(inode);
+               err = inode_permission(lower_inode, mask);
+
+               REVERT_CRED();
+       }
+#endif
+       return err;
+
+}
+
+static int sdcardfs_setattr(struct dentry *dentry, struct iattr *ia)
+{
+       int err;
+       struct dentry *lower_dentry;
+       struct inode *inode;
+       struct inode *lower_inode;
+       struct path lower_path;
+       struct iattr lower_ia;
+       struct dentry *parent;
+
+       inode = d_inode(dentry);
+
+       /*
+        * Check if user has permission to change inode.  We don't check if
+        * this user can change the lower inode: that should happen when
+        * calling notify_change on the lower inode.
+        */
+       err = inode_change_ok(inode, ia);
+
+       /* no vfs_XXX operations required, cred overriding will be skipped. wj*/
+       if (!err) {
+               /* check the Android group ID */
+               parent = dget_parent(dentry);
+               if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
+                       printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                        "  dentry: %s, task:%s\n",
+                                                        __func__, dentry->d_name.name, current->comm);
+                       err = -EACCES;
+               }
+               dput(parent);
+       }
+
+       if (err)
+               goto out_err;
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_inode = sdcardfs_lower_inode(inode);
+
+       /* prepare our own lower struct iattr (with the lower file) */
+       memcpy(&lower_ia, ia, sizeof(lower_ia));
+       if (ia->ia_valid & ATTR_FILE)
+               lower_ia.ia_file = sdcardfs_lower_file(ia->ia_file);
+
+       lower_ia.ia_valid &= ~(ATTR_UID | ATTR_GID | ATTR_MODE);
+
+       /*
+        * If shrinking, first truncate upper level to cancel writing dirty
+        * pages beyond the new eof; and also if its' maxbytes is more
+        * limiting (fail with -EFBIG before making any change to the lower
+        * level).  There is no need to vmtruncate the upper level
+        * afterwards in the other cases: we fsstack_copy_inode_size from
+        * the lower level.
+        */
+       if (current->mm)
+               down_write(&current->mm->mmap_sem);
+       if (ia->ia_valid & ATTR_SIZE) {
+               err = inode_newsize_ok(inode, ia->ia_size);
+               if (err) {
+                       if (current->mm)
+                               up_write(&current->mm->mmap_sem);
+                       goto out;
+               }
+               truncate_setsize(inode, ia->ia_size);
+       }
+
+       /*
+        * mode change is for clearing setuid/setgid bits. Allow lower fs
+        * to interpret this in its own way.
+        */
+       if (lower_ia.ia_valid & (ATTR_KILL_SUID | ATTR_KILL_SGID))
+               lower_ia.ia_valid &= ~ATTR_MODE;
+
+       /* notify the (possibly copied-up) lower inode */
+       /*
+        * Note: we use d_inode(lower_dentry), because lower_inode may be
+        * unlinked (no inode->i_sb and i_ino==0.  This happens if someone
+        * tries to open(), unlink(), then ftruncate() a file.
+        */
+       mutex_lock(&d_inode(lower_dentry)->i_mutex);
+       err = notify_change(lower_dentry, &lower_ia, /* note: lower_ia */
+                       NULL);
+       mutex_unlock(&d_inode(lower_dentry)->i_mutex);
+       if (current->mm)
+               up_write(&current->mm->mmap_sem);
+       if (err)
+               goto out;
+
+       /* get attributes from the lower inode and update derived permissions */
+       sdcardfs_copy_and_fix_attrs(inode, lower_inode);
+
+       /*
+        * Not running fsstack_copy_inode_size(inode, lower_inode), because
+        * VFS should update our inode size, and notify_change on
+        * lower_inode should update its size.
+        */
+
+out:
+       sdcardfs_put_lower_path(dentry, &lower_path);
+out_err:
+       return err;
+}
+
+static int sdcardfs_getattr(struct vfsmount *mnt, struct dentry *dentry,
+                struct kstat *stat)
+{
+       struct dentry *lower_dentry;
+       struct inode *inode;
+       struct inode *lower_inode;
+       struct path lower_path;
+       struct dentry *parent;
+
+       parent = dget_parent(dentry);
+       if(!check_caller_access_to_name(d_inode(parent), dentry->d_name.name)) {
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                                                "  dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               dput(parent);
+               return -EACCES;
+       }
+       dput(parent);
+
+       inode = d_inode(dentry);
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       lower_dentry = lower_path.dentry;
+       lower_inode = sdcardfs_lower_inode(inode);
+
+
+       sdcardfs_copy_and_fix_attrs(inode, lower_inode);
+       fsstack_copy_inode_size(inode, lower_inode);
+
+
+       generic_fillattr(inode, stat);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+       return 0;
+}
+
+const struct inode_operations sdcardfs_symlink_iops = {
+       .permission     = sdcardfs_permission,
+       .setattr        = sdcardfs_setattr,
+       /* XXX Following operations are implemented,
+        *     but FUSE(sdcard) or FAT does not support them
+        *     These methods are *NOT* perfectly tested.
+       .readlink       = sdcardfs_readlink,
+       .follow_link    = sdcardfs_follow_link,
+       .put_link       = kfree_put_link,
+        */
+};
+
+const struct inode_operations sdcardfs_dir_iops = {
+       .create         = sdcardfs_create,
+       .lookup         = sdcardfs_lookup,
+#if 0
+       .permission     = sdcardfs_permission,
+#endif
+       .unlink         = sdcardfs_unlink,
+       .mkdir          = sdcardfs_mkdir,
+       .rmdir          = sdcardfs_rmdir,
+       .rename         = sdcardfs_rename,
+       .setattr        = sdcardfs_setattr,
+       .getattr        = sdcardfs_getattr,
+       /* XXX Following operations are implemented,
+        *     but FUSE(sdcard) or FAT does not support them
+        *     These methods are *NOT* perfectly tested.
+       .symlink        = sdcardfs_symlink,
+       .link           = sdcardfs_link,
+       .mknod          = sdcardfs_mknod,
+        */
+};
+
+const struct inode_operations sdcardfs_main_iops = {
+       .permission     = sdcardfs_permission,
+       .setattr        = sdcardfs_setattr,
+       .getattr        = sdcardfs_getattr,
+};
diff --git a/fs/sdcardfs/lookup.c b/fs/sdcardfs/lookup.c
new file mode 100644 (file)
index 0000000..a01b06a
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * fs/sdcardfs/lookup.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+#include "linux/delay.h"
+
+/* The dentry cache is just so we have properly sized dentries */
+static struct kmem_cache *sdcardfs_dentry_cachep;
+
+int sdcardfs_init_dentry_cache(void)
+{
+       sdcardfs_dentry_cachep =
+               kmem_cache_create("sdcardfs_dentry",
+                                 sizeof(struct sdcardfs_dentry_info),
+                                 0, SLAB_RECLAIM_ACCOUNT, NULL);
+
+       return sdcardfs_dentry_cachep ? 0 : -ENOMEM;
+}
+
+void sdcardfs_destroy_dentry_cache(void)
+{
+       if (sdcardfs_dentry_cachep)
+               kmem_cache_destroy(sdcardfs_dentry_cachep);
+}
+
+void free_dentry_private_data(struct dentry *dentry)
+{
+       if (!dentry || !dentry->d_fsdata)
+               return;
+       kmem_cache_free(sdcardfs_dentry_cachep, dentry->d_fsdata);
+       dentry->d_fsdata = NULL;
+}
+
+/* allocate new dentry private data */
+int new_dentry_private_data(struct dentry *dentry)
+{
+       struct sdcardfs_dentry_info *info = SDCARDFS_D(dentry);
+
+       /* use zalloc to init dentry_info.lower_path */
+       info = kmem_cache_zalloc(sdcardfs_dentry_cachep, GFP_ATOMIC);
+       if (!info)
+               return -ENOMEM;
+
+       spin_lock_init(&info->lock);
+       dentry->d_fsdata = info;
+
+       return 0;
+}
+
+struct inode_data {
+       struct inode *lower_inode;
+       userid_t id;
+};
+
+static int sdcardfs_inode_test(struct inode *inode, void *candidate_data/*void *candidate_lower_inode*/)
+{
+       struct inode *current_lower_inode = sdcardfs_lower_inode(inode);
+       userid_t current_userid = SDCARDFS_I(inode)->userid;
+       if (current_lower_inode == ((struct inode_data *)candidate_data)->lower_inode &&
+                       current_userid == ((struct inode_data *)candidate_data)->id)
+               return 1; /* found a match */
+       else
+               return 0; /* no match */
+}
+
+static int sdcardfs_inode_set(struct inode *inode, void *lower_inode)
+{
+       /* we do actual inode initialization in sdcardfs_iget */
+       return 0;
+}
+
+struct inode *sdcardfs_iget(struct super_block *sb, struct inode *lower_inode, userid_t id)
+{
+       struct sdcardfs_inode_info *info;
+       struct inode_data data;
+       struct inode *inode; /* the new inode to return */
+       int err;
+
+       data.id = id;
+       data.lower_inode = lower_inode;
+       inode = iget5_locked(sb, /* our superblock */
+                            /*
+                             * hashval: we use inode number, but we can
+                             * also use "(unsigned long)lower_inode"
+                             * instead.
+                             */
+                            lower_inode->i_ino, /* hashval */
+                            sdcardfs_inode_test,       /* inode comparison function */
+                            sdcardfs_inode_set, /* inode init function */
+                            &data); /* data passed to test+set fxns */
+       if (!inode) {
+               err = -EACCES;
+               iput(lower_inode);
+               return ERR_PTR(err);
+       }
+       /* if found a cached inode, then just return it */
+       if (!(inode->i_state & I_NEW))
+               return inode;
+
+       /* initialize new inode */
+       info = SDCARDFS_I(inode);
+
+       inode->i_ino = lower_inode->i_ino;
+       if (!igrab(lower_inode)) {
+               err = -ESTALE;
+               return ERR_PTR(err);
+       }
+       sdcardfs_set_lower_inode(inode, lower_inode);
+
+       inode->i_version++;
+
+       /* use different set of inode ops for symlinks & directories */
+       if (S_ISDIR(lower_inode->i_mode))
+               inode->i_op = &sdcardfs_dir_iops;
+       else if (S_ISLNK(lower_inode->i_mode))
+               inode->i_op = &sdcardfs_symlink_iops;
+       else
+               inode->i_op = &sdcardfs_main_iops;
+
+       /* use different set of file ops for directories */
+       if (S_ISDIR(lower_inode->i_mode))
+               inode->i_fop = &sdcardfs_dir_fops;
+       else
+               inode->i_fop = &sdcardfs_main_fops;
+
+       inode->i_mapping->a_ops = &sdcardfs_aops;
+
+       inode->i_atime.tv_sec = 0;
+       inode->i_atime.tv_nsec = 0;
+       inode->i_mtime.tv_sec = 0;
+       inode->i_mtime.tv_nsec = 0;
+       inode->i_ctime.tv_sec = 0;
+       inode->i_ctime.tv_nsec = 0;
+
+       /* properly initialize special inodes */
+       if (S_ISBLK(lower_inode->i_mode) || S_ISCHR(lower_inode->i_mode) ||
+           S_ISFIFO(lower_inode->i_mode) || S_ISSOCK(lower_inode->i_mode))
+               init_special_inode(inode, lower_inode->i_mode,
+                                  lower_inode->i_rdev);
+
+       /* all well, copy inode attributes */
+       sdcardfs_copy_and_fix_attrs(inode, lower_inode);
+       fsstack_copy_inode_size(inode, lower_inode);
+
+       unlock_new_inode(inode);
+       return inode;
+}
+
+/*
+ * Connect a sdcardfs inode dentry/inode with several lower ones.  This is
+ * the classic stackable file system "vnode interposition" action.
+ *
+ * @dentry: sdcardfs's dentry which interposes on lower one
+ * @sb: sdcardfs's super_block
+ * @lower_path: the lower path (caller does path_get/put)
+ */
+int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
+                    struct path *lower_path, userid_t id)
+{
+       int err = 0;
+       struct inode *inode;
+       struct inode *lower_inode;
+       struct super_block *lower_sb;
+
+       lower_inode = lower_path->dentry->d_inode;
+       lower_sb = sdcardfs_lower_super(sb);
+
+       /* check that the lower file system didn't cross a mount point */
+       if (lower_inode->i_sb != lower_sb) {
+               err = -EXDEV;
+               goto out;
+       }
+
+       /*
+        * We allocate our new inode below by calling sdcardfs_iget,
+        * which will initialize some of the new inode's fields
+        */
+
+       /* inherit lower inode number for sdcardfs's inode */
+       inode = sdcardfs_iget(sb, lower_inode, id);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
+               goto out;
+       }
+
+       d_add(dentry, inode);
+       update_derived_permission_lock(dentry);
+out:
+       return err;
+}
+
+/*
+ * Main driver function for sdcardfs's lookup.
+ *
+ * Returns: NULL (ok), ERR_PTR if an error occurred.
+ * Fills in lower_parent_path with <dentry,mnt> on success.
+ */
+static struct dentry *__sdcardfs_lookup(struct dentry *dentry,
+               unsigned int flags, struct path *lower_parent_path, userid_t id)
+{
+       int err = 0;
+       struct vfsmount *lower_dir_mnt;
+       struct dentry *lower_dir_dentry = NULL;
+       struct dentry *lower_dentry;
+       const char *name;
+       struct path lower_path;
+       struct qstr this;
+       struct sdcardfs_sb_info *sbi;
+
+       sbi = SDCARDFS_SB(dentry->d_sb);
+       /* must initialize dentry operations */
+       d_set_d_op(dentry, &sdcardfs_ci_dops);
+
+       if (IS_ROOT(dentry))
+               goto out;
+
+       name = dentry->d_name.name;
+
+       /* now start the actual lookup procedure */
+       lower_dir_dentry = lower_parent_path->dentry;
+       lower_dir_mnt = lower_parent_path->mnt;
+
+       /* Use vfs_path_lookup to check if the dentry exists or not */
+       err = vfs_path_lookup(lower_dir_dentry, lower_dir_mnt, name, 0,
+                               &lower_path);
+
+       /* no error: handle positive dentries */
+       if (!err) {
+               /* check if the dentry is an obb dentry
+                * if true, the lower_inode must be replaced with
+                * the inode of the graft path */
+
+               if(need_graft_path(dentry)) {
+
+                       /* setup_obb_dentry()
+                        * The lower_path will be stored to the dentry's orig_path
+                        * and the base obbpath will be copyed to the lower_path variable.
+                        * if an error returned, there's no change in the lower_path
+                        *              returns: -ERRNO if error (0: no error) */
+                       err = setup_obb_dentry(dentry, &lower_path);
+
+                       if(err) {
+                               /* if the sbi->obbpath is not available, we can optionally
+                                * setup the lower_path with its orig_path.
+                                * but, the current implementation just returns an error
+                                * because the sdcard daemon also regards this case as
+                                * a lookup fail. */
+                               printk(KERN_INFO "sdcardfs: base obbpath is not available\n");
+                               sdcardfs_put_reset_orig_path(dentry);
+                               goto out;
+                       }
+               }
+
+               sdcardfs_set_lower_path(dentry, &lower_path);
+               err = sdcardfs_interpose(dentry, dentry->d_sb, &lower_path, id);
+               if (err) /* path_put underlying path on error */
+                       sdcardfs_put_reset_lower_path(dentry);
+               goto out;
+       }
+
+       /*
+        * We don't consider ENOENT an error, and we want to return a
+        * negative dentry.
+        */
+       if (err && err != -ENOENT)
+               goto out;
+
+       /* instatiate a new negative dentry */
+       this.name = name;
+       this.len = strlen(name);
+       this.hash = full_name_hash(this.name, this.len);
+       lower_dentry = d_lookup(lower_dir_dentry, &this);
+       if (lower_dentry)
+               goto setup_lower;
+
+       lower_dentry = d_alloc(lower_dir_dentry, &this);
+       if (!lower_dentry) {
+               err = -ENOMEM;
+               goto out;
+       }
+       d_add(lower_dentry, NULL); /* instantiate and hash */
+
+setup_lower:
+       lower_path.dentry = lower_dentry;
+       lower_path.mnt = mntget(lower_dir_mnt);
+       sdcardfs_set_lower_path(dentry, &lower_path);
+
+       /*
+        * If the intent is to create a file, then don't return an error, so
+        * the VFS will continue the process of making this negative dentry
+        * into a positive one.
+        */
+       if (flags & (LOOKUP_CREATE|LOOKUP_RENAME_TARGET))
+               err = 0;
+
+out:
+       return ERR_PTR(err);
+}
+
+/*
+ * On success:
+ *     fills dentry object appropriate values and returns NULL.
+ * On fail (== error)
+ *     returns error ptr
+ *
+ * @dir : Parent inode. It is locked (dir->i_mutex)
+ * @dentry : Target dentry to lookup. we should set each of fields.
+ *          (dentry->d_name is initialized already)
+ * @nd : nameidata of parent inode
+ */
+struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
+                            unsigned int flags)
+{
+       struct dentry *ret = NULL, *parent;
+       struct path lower_parent_path;
+       int err = 0;
+       const struct cred *saved_cred = NULL;
+
+       parent = dget_parent(dentry);
+
+       if(!check_caller_access_to_name(parent->d_inode, dentry->d_name.name)) {
+               ret = ERR_PTR(-EACCES);
+               printk(KERN_INFO "%s: need to check the caller's gid in packages.list\n"
+                         "     dentry: %s, task:%s\n",
+                                                __func__, dentry->d_name.name, current->comm);
+               goto out_err;
+        }
+
+       /* save current_cred and override it */
+       OVERRIDE_CRED_PTR(SDCARDFS_SB(dir->i_sb), saved_cred);
+
+       sdcardfs_get_lower_path(parent, &lower_parent_path);
+
+       /* allocate dentry private data.  We free it in ->d_release */
+       err = new_dentry_private_data(dentry);
+       if (err) {
+               ret = ERR_PTR(err);
+               goto out;
+       }
+
+       ret = __sdcardfs_lookup(dentry, flags, &lower_parent_path, SDCARDFS_I(dir)->userid);
+       if (IS_ERR(ret))
+       {
+               goto out;
+       }
+       if (ret)
+               dentry = ret;
+       if (dentry->d_inode) {
+               fsstack_copy_attr_times(dentry->d_inode,
+                                       sdcardfs_lower_inode(dentry->d_inode));
+               /* get drived permission */
+               mutex_lock(&dentry->d_inode->i_mutex);
+               get_derived_permission(parent, dentry);
+               fix_derived_permission(dentry->d_inode);
+               mutex_unlock(&dentry->d_inode->i_mutex);
+       }
+       /* update parent directory's atime */
+       fsstack_copy_attr_atime(parent->d_inode,
+                               sdcardfs_lower_inode(parent->d_inode));
+
+out:
+       sdcardfs_put_lower_path(parent, &lower_parent_path);
+       REVERT_CRED(saved_cred);
+out_err:
+       dput(parent);
+       return ret;
+}
diff --git a/fs/sdcardfs/main.c b/fs/sdcardfs/main.c
new file mode 100644 (file)
index 0000000..a652228
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * fs/sdcardfs/main.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+#include <linux/module.h>
+#include <linux/types.h>
+#include <linux/parser.h>
+
+enum {
+       Opt_fsuid,
+       Opt_fsgid,
+       Opt_gid,
+       Opt_debug,
+       Opt_lower_fs,
+       Opt_mask,
+       Opt_multiuser, // May need?
+       Opt_userid,
+       Opt_reserved_mb,
+       Opt_err,
+};
+
+static const match_table_t sdcardfs_tokens = {
+       {Opt_fsuid, "fsuid=%u"},
+       {Opt_fsgid, "fsgid=%u"},
+       {Opt_gid, "gid=%u"},
+       {Opt_debug, "debug"},
+       {Opt_mask, "mask=%u"},
+       {Opt_userid, "userid=%d"},
+       {Opt_multiuser, "multiuser"},
+       {Opt_reserved_mb, "reserved_mb=%u"},
+       {Opt_err, NULL}
+};
+
+static int parse_options(struct super_block *sb, char *options, int silent,
+                               int *debug, struct sdcardfs_mount_options *opts)
+{
+       char *p;
+       substring_t args[MAX_OPT_ARGS];
+       int option;
+
+       /* by default, we use AID_MEDIA_RW as uid, gid */
+       opts->fs_low_uid = AID_MEDIA_RW;
+       opts->fs_low_gid = AID_MEDIA_RW;
+       opts->mask = 0;
+       opts->multiuser = false;
+       opts->fs_user_id = 0;
+       opts->gid = 0;
+       /* by default, 0MB is reserved */
+       opts->reserved_mb = 0;
+
+       *debug = 0;
+
+       if (!options)
+               return 0;
+
+       while ((p = strsep(&options, ",")) != NULL) {
+               int token;
+               if (!*p)
+                       continue;
+
+               token = match_token(p, sdcardfs_tokens, args);
+
+               switch (token) {
+               case Opt_debug:
+                       *debug = 1;
+                       break;
+               case Opt_fsuid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->fs_low_uid = option;
+                       break;
+               case Opt_fsgid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->fs_low_gid = option;
+                       break;
+               case Opt_gid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->gid = option;
+                       break;
+               case Opt_userid:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->fs_user_id = option;
+                       break;
+               case Opt_mask:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->mask = option;
+                       break;
+               case Opt_multiuser:
+                       opts->multiuser = true;
+                       break;
+               case Opt_reserved_mb:
+                       if (match_int(&args[0], &option))
+                               return 0;
+                       opts->reserved_mb = option;
+                       break;
+               /* unknown option */
+               default:
+                       if (!silent) {
+                               printk( KERN_ERR "Unrecognized mount option \"%s\" "
+                                               "or missing value", p);
+                       }
+                       return -EINVAL;
+               }
+       }
+
+       if (*debug) {
+               printk( KERN_INFO "sdcardfs : options - debug:%d\n", *debug);
+               printk( KERN_INFO "sdcardfs : options - uid:%d\n",
+                                                       opts->fs_low_uid);
+               printk( KERN_INFO "sdcardfs : options - gid:%d\n",
+                                                       opts->fs_low_gid);
+       }
+
+       return 0;
+}
+
+#if 0
+/*
+ * our custom d_alloc_root work-alike
+ *
+ * we can't use d_alloc_root if we want to use our own interpose function
+ * unchanged, so we simply call our own "fake" d_alloc_root
+ */
+static struct dentry *sdcardfs_d_alloc_root(struct super_block *sb)
+{
+       struct dentry *ret = NULL;
+
+       if (sb) {
+               static const struct qstr name = {
+                       .name = "/",
+                       .len = 1
+               };
+
+               ret = d_alloc(NULL, &name);
+               if (ret) {
+                       d_set_d_op(ret, &sdcardfs_ci_dops);
+                       ret->d_sb = sb;
+                       ret->d_parent = ret;
+               }
+       }
+       return ret;
+}
+#endif
+
+DEFINE_MUTEX(sdcardfs_super_list_lock);
+LIST_HEAD(sdcardfs_super_list);
+EXPORT_SYMBOL_GPL(sdcardfs_super_list_lock);
+EXPORT_SYMBOL_GPL(sdcardfs_super_list);
+
+/*
+ * There is no need to lock the sdcardfs_super_info's rwsem as there is no
+ * way anyone can have a reference to the superblock at this point in time.
+ */
+static int sdcardfs_read_super(struct super_block *sb, const char *dev_name,
+                                               void *raw_data, int silent)
+{
+       int err = 0;
+       int debug;
+       struct super_block *lower_sb;
+       struct path lower_path;
+       struct sdcardfs_sb_info *sb_info;
+       struct inode *inode;
+
+       printk(KERN_INFO "sdcardfs version 2.0\n");
+
+       if (!dev_name) {
+               printk(KERN_ERR
+                      "sdcardfs: read_super: missing dev_name argument\n");
+               err = -EINVAL;
+               goto out;
+       }
+
+       printk(KERN_INFO "sdcardfs: dev_name -> %s\n", dev_name);
+       printk(KERN_INFO "sdcardfs: options -> %s\n", (char *)raw_data);
+
+       /* parse lower path */
+       err = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY,
+                       &lower_path);
+       if (err) {
+               printk(KERN_ERR "sdcardfs: error accessing lower directory '%s'\n", dev_name);
+               goto out;
+       }
+
+       /* allocate superblock private data */
+       sb->s_fs_info = kzalloc(sizeof(struct sdcardfs_sb_info), GFP_KERNEL);
+       if (!SDCARDFS_SB(sb)) {
+               printk(KERN_CRIT "sdcardfs: read_super: out of memory\n");
+               err = -ENOMEM;
+               goto out_free;
+       }
+
+       sb_info = sb->s_fs_info;
+       /* parse options */
+       err = parse_options(sb, raw_data, silent, &debug, &sb_info->options);
+       if (err) {
+               printk(KERN_ERR "sdcardfs: invalid options\n");
+               goto out_freesbi;
+       }
+
+       /* set the lower superblock field of upper superblock */
+       lower_sb = lower_path.dentry->d_sb;
+       atomic_inc(&lower_sb->s_active);
+       sdcardfs_set_lower_super(sb, lower_sb);
+
+       /* inherit maxbytes from lower file system */
+       sb->s_maxbytes = lower_sb->s_maxbytes;
+
+       /*
+        * Our c/m/atime granularity is 1 ns because we may stack on file
+        * systems whose granularity is as good.
+        */
+       sb->s_time_gran = 1;
+
+       sb->s_magic = SDCARDFS_SUPER_MAGIC;
+       sb->s_op = &sdcardfs_sops;
+
+       /* get a new inode and allocate our root dentry */
+       inode = sdcardfs_iget(sb, lower_path.dentry->d_inode, 0);
+       if (IS_ERR(inode)) {
+               err = PTR_ERR(inode);
+               goto out_sput;
+       }
+       sb->s_root = d_make_root(inode);
+       if (!sb->s_root) {
+               err = -ENOMEM;
+               goto out_iput;
+       }
+       d_set_d_op(sb->s_root, &sdcardfs_ci_dops);
+
+       /* link the upper and lower dentries */
+       sb->s_root->d_fsdata = NULL;
+       err = new_dentry_private_data(sb->s_root);
+       if (err)
+               goto out_freeroot;
+
+       /* set the lower dentries for s_root */
+       sdcardfs_set_lower_path(sb->s_root, &lower_path);
+
+       /*
+        * No need to call interpose because we already have a positive
+        * dentry, which was instantiated by d_make_root.  Just need to
+        * d_rehash it.
+        */
+       d_rehash(sb->s_root);
+
+       /* setup permission policy */
+       sb_info->obbpath_s = kzalloc(PATH_MAX, GFP_KERNEL);
+       mutex_lock(&sdcardfs_super_list_lock);
+       if(sb_info->options.multiuser) {
+               setup_derived_state(sb->s_root->d_inode, PERM_PRE_ROOT, sb_info->options.fs_user_id, AID_ROOT, false);
+               snprintf(sb_info->obbpath_s, PATH_MAX, "%s/obb", dev_name);
+               /*err =  prepare_dir(sb_info->obbpath_s,
+                                       sb_info->options.fs_low_uid,
+                                       sb_info->options.fs_low_gid, 00755);*/
+       } else {
+               setup_derived_state(sb->s_root->d_inode, PERM_ROOT, sb_info->options.fs_low_uid, AID_ROOT, false);
+               snprintf(sb_info->obbpath_s, PATH_MAX, "%s/Android/obb", dev_name);
+       }
+       fix_derived_permission(sb->s_root->d_inode);
+       sb_info->sb = sb;
+       list_add(&sb_info->list, &sdcardfs_super_list);
+       mutex_unlock(&sdcardfs_super_list_lock);
+
+       if (!silent)
+               printk(KERN_INFO "sdcardfs: mounted on top of %s type %s\n",
+                               dev_name, lower_sb->s_type->name);
+       goto out; /* all is well */
+
+       /* no longer needed: free_dentry_private_data(sb->s_root); */
+out_freeroot:
+       dput(sb->s_root);
+out_iput:
+       iput(inode);
+out_sput:
+       /* drop refs we took earlier */
+       atomic_dec(&lower_sb->s_active);
+out_freesbi:
+       kfree(SDCARDFS_SB(sb));
+       sb->s_fs_info = NULL;
+out_free:
+       path_put(&lower_path);
+
+out:
+       return err;
+}
+
+/* A feature which supports mount_nodev() with options */
+static struct dentry *mount_nodev_with_options(struct file_system_type *fs_type,
+        int flags, const char *dev_name, void *data,
+        int (*fill_super)(struct super_block *, const char *, void *, int))
+
+{
+       int error;
+       struct super_block *s = sget(fs_type, NULL, set_anon_super, flags, NULL);
+
+       if (IS_ERR(s))
+               return ERR_CAST(s);
+
+       s->s_flags = flags;
+
+       error = fill_super(s, dev_name, data, flags & MS_SILENT ? 1 : 0);
+       if (error) {
+               deactivate_locked_super(s);
+               return ERR_PTR(error);
+       }
+       s->s_flags |= MS_ACTIVE;
+       return dget(s->s_root);
+}
+
+struct dentry *sdcardfs_mount(struct file_system_type *fs_type, int flags,
+                           const char *dev_name, void *raw_data)
+{
+       /*
+        * dev_name is a lower_path_name,
+        * raw_data is a option string.
+        */
+       return mount_nodev_with_options(fs_type, flags, dev_name,
+                                       raw_data, sdcardfs_read_super);
+}
+
+void sdcardfs_kill_sb(struct super_block *sb) {
+       struct sdcardfs_sb_info *sbi;
+       if (sb->s_magic == SDCARDFS_SUPER_MAGIC) {
+               sbi = SDCARDFS_SB(sb);
+               mutex_lock(&sdcardfs_super_list_lock);
+               list_del(&sbi->list);
+               mutex_unlock(&sdcardfs_super_list_lock);
+       }
+       generic_shutdown_super(sb);
+}
+
+static struct file_system_type sdcardfs_fs_type = {
+       .owner          = THIS_MODULE,
+       .name           = SDCARDFS_NAME,
+       .mount          = sdcardfs_mount,
+       .kill_sb        = sdcardfs_kill_sb,
+       .fs_flags       = 0,
+};
+
+static int __init init_sdcardfs_fs(void)
+{
+       int err;
+
+       pr_info("Registering sdcardfs " SDCARDFS_VERSION "\n");
+
+       err = sdcardfs_init_inode_cache();
+       if (err)
+               goto out;
+       err = sdcardfs_init_dentry_cache();
+       if (err)
+               goto out;
+       err = packagelist_init();
+       if (err)
+               goto out;
+       err = register_filesystem(&sdcardfs_fs_type);
+out:
+       if (err) {
+               sdcardfs_destroy_inode_cache();
+               sdcardfs_destroy_dentry_cache();
+               packagelist_exit();
+       }
+       return err;
+}
+
+static void __exit exit_sdcardfs_fs(void)
+{
+       sdcardfs_destroy_inode_cache();
+       sdcardfs_destroy_dentry_cache();
+       packagelist_exit();
+       unregister_filesystem(&sdcardfs_fs_type);
+       pr_info("Completed sdcardfs module unload\n");
+}
+
+MODULE_AUTHOR("Erez Zadok, Filesystems and Storage Lab, Stony Brook University"
+             " (http://www.fsl.cs.sunysb.edu/)");
+MODULE_DESCRIPTION("Wrapfs " SDCARDFS_VERSION
+                  " (http://wrapfs.filesystems.org/)");
+MODULE_LICENSE("GPL");
+
+module_init(init_sdcardfs_fs);
+module_exit(exit_sdcardfs_fs);
diff --git a/fs/sdcardfs/mmap.c b/fs/sdcardfs/mmap.c
new file mode 100644 (file)
index 0000000..e21f646
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * fs/sdcardfs/mmap.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+
+static int sdcardfs_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
+{
+       int err;
+       struct file *file, *lower_file;
+       const struct vm_operations_struct *lower_vm_ops;
+       struct vm_area_struct lower_vma;
+
+       memcpy(&lower_vma, vma, sizeof(struct vm_area_struct));
+       file = lower_vma.vm_file;
+       lower_vm_ops = SDCARDFS_F(file)->lower_vm_ops;
+       BUG_ON(!lower_vm_ops);
+
+       lower_file = sdcardfs_lower_file(file);
+       /*
+        * XXX: vm_ops->fault may be called in parallel.  Because we have to
+        * resort to temporarily changing the vma->vm_file to point to the
+        * lower file, a concurrent invocation of sdcardfs_fault could see a
+        * different value.  In this workaround, we keep a different copy of
+        * the vma structure in our stack, so we never expose a different
+        * value of the vma->vm_file called to us, even temporarily.  A
+        * better fix would be to change the calling semantics of ->fault to
+        * take an explicit file pointer.
+        */
+       lower_vma.vm_file = lower_file;
+       err = lower_vm_ops->fault(&lower_vma, vmf);
+       return err;
+}
+
+static ssize_t sdcardfs_direct_IO(struct kiocb *iocb,
+               struct iov_iter *iter, loff_t pos)
+{
+       /*
+     * This function returns zero on purpose in order to support direct IO.
+        * __dentry_open checks a_ops->direct_IO and returns EINVAL if it is null.
+     *
+        * However, this function won't be called by certain file operations
+     * including generic fs functions.  * reads and writes are delivered to
+     * the lower file systems and the direct IOs will be handled by them.
+        *
+     * NOTE: exceptionally, on the recent kernels (since Linux 3.8.x),
+     * swap_writepage invokes this function directly.
+        */
+       printk(KERN_INFO "%s, operation is not supported\n", __func__);
+       return 0;
+}
+
+/*
+ * XXX: the default address_space_ops for sdcardfs is empty.  We cannot set
+ * our inode->i_mapping->a_ops to NULL because too many code paths expect
+ * the a_ops vector to be non-NULL.
+ */
+const struct address_space_operations sdcardfs_aops = {
+       /* empty on purpose */
+       .direct_IO      = sdcardfs_direct_IO,
+};
+
+const struct vm_operations_struct sdcardfs_vm_ops = {
+       .fault          = sdcardfs_fault,
+};
diff --git a/fs/sdcardfs/multiuser.h b/fs/sdcardfs/multiuser.h
new file mode 100644 (file)
index 0000000..923ba10
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * fs/sdcardfs/multiuser.h
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#define MULTIUSER_APP_PER_USER_RANGE 100000
+
+typedef uid_t userid_t;
+typedef uid_t appid_t;
+
+static inline userid_t multiuser_get_user_id(uid_t uid) {
+    return uid / MULTIUSER_APP_PER_USER_RANGE;
+}
+
+static inline appid_t multiuser_get_app_id(uid_t uid) {
+    return uid % MULTIUSER_APP_PER_USER_RANGE;
+}
+
+static inline uid_t multiuser_get_uid(userid_t userId, appid_t appId) {
+    return userId * MULTIUSER_APP_PER_USER_RANGE + (appId % MULTIUSER_APP_PER_USER_RANGE);
+}
+
diff --git a/fs/sdcardfs/packagelist.c b/fs/sdcardfs/packagelist.c
new file mode 100644 (file)
index 0000000..10f0d6b
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ * fs/sdcardfs/packagelist.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+#include <linux/hashtable.h>
+#include <linux/delay.h>
+
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+
+#include <linux/configfs.h>
+
+#define STRING_BUF_SIZE                (512)
+
+struct hashtable_entry {
+       struct hlist_node hlist;
+       void *key;
+       unsigned int value;
+};
+
+struct sb_list {
+       struct super_block *sb;
+       struct list_head list;
+};
+
+struct packagelist_data {
+       DECLARE_HASHTABLE(package_to_appid,8);
+       struct mutex hashtable_lock;
+
+};
+
+static struct packagelist_data *pkgl_data_all;
+
+static struct kmem_cache *hashtable_entry_cachep;
+
+static unsigned int str_hash(const char *key) {
+       int i;
+       unsigned int h = strlen(key);
+       char *data = (char *)key;
+
+       for (i = 0; i < strlen(key); i++) {
+               h = h * 31 + *data;
+               data++;
+       }
+       return h;
+}
+
+appid_t get_appid(void *pkgl_id, const char *app_name)
+{
+       struct packagelist_data *pkgl_dat = pkgl_data_all;
+       struct hashtable_entry *hash_cur;
+       unsigned int hash = str_hash(app_name);
+       appid_t ret_id;
+
+       mutex_lock(&pkgl_dat->hashtable_lock);
+       hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
+               if (!strcasecmp(app_name, hash_cur->key)) {
+                       ret_id = (appid_t)hash_cur->value;
+                       mutex_unlock(&pkgl_dat->hashtable_lock);
+                       return ret_id;
+               }
+       }
+       mutex_unlock(&pkgl_dat->hashtable_lock);
+       return 0;
+}
+
+/* Kernel has already enforced everything we returned through
+ * derive_permissions_locked(), so this is used to lock down access
+ * even further, such as enforcing that apps hold sdcard_rw. */
+int check_caller_access_to_name(struct inode *parent_node, const char* name) {
+
+       /* Always block security-sensitive files at root */
+       if (parent_node && SDCARDFS_I(parent_node)->perm == PERM_ROOT) {
+               if (!strcasecmp(name, "autorun.inf")
+                       || !strcasecmp(name, ".android_secure")
+                       || !strcasecmp(name, "android_secure")) {
+                       return 0;
+               }
+       }
+
+       /* Root always has access; access for any other UIDs should always
+        * be controlled through packages.list. */
+       if (from_kuid(&init_user_ns, current_fsuid()) == 0) {
+               return 1;
+       }
+
+       /* No extra permissions to enforce */
+       return 1;
+}
+
+/* This function is used when file opening. The open flags must be
+ * checked before calling check_caller_access_to_name() */
+int open_flags_to_access_mode(int open_flags) {
+       if((open_flags & O_ACCMODE) == O_RDONLY) {
+               return 0; /* R_OK */
+       } else if ((open_flags & O_ACCMODE) == O_WRONLY) {
+               return 1; /* W_OK */
+       } else {
+               /* Probably O_RDRW, but treat as default to be safe */
+               return 1; /* R_OK | W_OK */
+       }
+}
+
+static int insert_str_to_int_lock(struct packagelist_data *pkgl_dat, char *key,
+               unsigned int value)
+{
+       struct hashtable_entry *hash_cur;
+       struct hashtable_entry *new_entry;
+       unsigned int hash = str_hash(key);
+
+       hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
+               if (!strcasecmp(key, hash_cur->key)) {
+                       hash_cur->value = value;
+                       return 0;
+               }
+       }
+       new_entry = kmem_cache_alloc(hashtable_entry_cachep, GFP_KERNEL);
+       if (!new_entry)
+               return -ENOMEM;
+       new_entry->key = kstrdup(key, GFP_KERNEL);
+       new_entry->value = value;
+       hash_add(pkgl_dat->package_to_appid, &new_entry->hlist, hash);
+       return 0;
+}
+
+static void fixup_perms(struct super_block *sb) {
+       if (sb && sb->s_magic == SDCARDFS_SUPER_MAGIC) {
+               mutex_lock(&sb->s_root->d_inode->i_mutex);
+               get_derive_permissions_recursive(sb->s_root);
+               mutex_unlock(&sb->s_root->d_inode->i_mutex);
+       }
+}
+
+static int insert_str_to_int(struct packagelist_data *pkgl_dat, char *key,
+               unsigned int value) {
+       int ret;
+       struct sdcardfs_sb_info *sbinfo;
+       mutex_lock(&sdcardfs_super_list_lock);
+       mutex_lock(&pkgl_dat->hashtable_lock);
+       ret = insert_str_to_int_lock(pkgl_dat, key, value);
+       mutex_unlock(&pkgl_dat->hashtable_lock);
+
+       list_for_each_entry(sbinfo, &sdcardfs_super_list, list) {
+               if (sbinfo) {
+                       fixup_perms(sbinfo->sb);
+               }
+       }
+       mutex_unlock(&sdcardfs_super_list_lock);
+       return ret;
+}
+
+static void remove_str_to_int_lock(struct hashtable_entry *h_entry) {
+       kfree(h_entry->key);
+       hash_del(&h_entry->hlist);
+       kmem_cache_free(hashtable_entry_cachep, h_entry);
+}
+
+static void remove_str_to_int(struct packagelist_data *pkgl_dat, const char *key)
+{
+       struct sdcardfs_sb_info *sbinfo;
+       struct hashtable_entry *hash_cur;
+       unsigned int hash = str_hash(key);
+       mutex_lock(&sdcardfs_super_list_lock);
+       mutex_lock(&pkgl_dat->hashtable_lock);
+       hash_for_each_possible(pkgl_dat->package_to_appid, hash_cur, hlist, hash) {
+               if (!strcasecmp(key, hash_cur->key)) {
+                       remove_str_to_int_lock(hash_cur);
+                       break;
+               }
+       }
+       mutex_unlock(&pkgl_dat->hashtable_lock);
+       list_for_each_entry(sbinfo, &sdcardfs_super_list, list) {
+               if (sbinfo) {
+                       fixup_perms(sbinfo->sb);
+               }
+       }
+       mutex_unlock(&sdcardfs_super_list_lock);
+       return;
+}
+
+static void remove_all_hashentrys(struct packagelist_data *pkgl_dat)
+{
+       struct hashtable_entry *hash_cur;
+       struct hlist_node *h_t;
+       int i;
+       mutex_lock(&pkgl_dat->hashtable_lock);
+       hash_for_each_safe(pkgl_dat->package_to_appid, i, h_t, hash_cur, hlist)
+               remove_str_to_int_lock(hash_cur);
+       mutex_unlock(&pkgl_dat->hashtable_lock);
+       hash_init(pkgl_dat->package_to_appid);
+}
+
+static struct packagelist_data * packagelist_create(void)
+{
+       struct packagelist_data *pkgl_dat;
+
+       pkgl_dat = kmalloc(sizeof(*pkgl_dat), GFP_KERNEL | __GFP_ZERO);
+       if (!pkgl_dat) {
+                printk(KERN_ERR "sdcardfs: Failed to create hash\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       mutex_init(&pkgl_dat->hashtable_lock);
+       hash_init(pkgl_dat->package_to_appid);
+
+       return pkgl_dat;
+}
+
+static void packagelist_destroy(struct packagelist_data *pkgl_dat)
+{
+       remove_all_hashentrys(pkgl_dat);
+       printk(KERN_INFO "sdcardfs: destroyed packagelist pkgld\n");
+       kfree(pkgl_dat);
+}
+
+struct package_appid {
+       struct config_item item;
+       int add_pid;
+};
+
+static inline struct package_appid *to_package_appid(struct config_item *item)
+{
+       return item ? container_of(item, struct package_appid, item) : NULL;
+}
+
+static ssize_t package_appid_attr_show(struct config_item *item,
+                                     char *page)
+{
+       ssize_t count;
+       count = sprintf(page, "%d\n", get_appid(pkgl_data_all, item->ci_name));
+       return count;
+}
+
+static ssize_t package_appid_attr_store(struct config_item *item,
+                                      const char *page, size_t count)
+{
+       struct package_appid *package_appid = to_package_appid(item);
+       unsigned long tmp;
+       char *p = (char *) page;
+       int ret;
+
+       tmp = simple_strtoul(p, &p, 10);
+       if (!p || (*p && (*p != '\n')))
+               return -EINVAL;
+
+       if (tmp > INT_MAX)
+               return -ERANGE;
+       ret = insert_str_to_int(pkgl_data_all, item->ci_name, (unsigned int)tmp);
+       package_appid->add_pid = tmp;
+       if (ret)
+               return ret;
+
+       return count;
+}
+
+static struct configfs_attribute package_appid_attr_add_pid = {
+       .ca_owner = THIS_MODULE,
+       .ca_name = "appid",
+       .ca_mode = S_IRUGO | S_IWUGO,
+       .show = package_appid_attr_show,
+       .store = package_appid_attr_store,
+};
+
+static struct configfs_attribute *package_appid_attrs[] = {
+       &package_appid_attr_add_pid,
+       NULL,
+};
+
+static void package_appid_release(struct config_item *item)
+{
+       printk(KERN_INFO "sdcardfs: removing %s\n", item->ci_dentry->d_name.name);
+       /* item->ci_name is freed already, so we rely on the dentry */
+       remove_str_to_int(pkgl_data_all, item->ci_dentry->d_name.name);
+       kfree(to_package_appid(item));
+}
+
+static struct configfs_item_operations package_appid_item_ops = {
+       .release                = package_appid_release,
+};
+
+static struct config_item_type package_appid_type = {
+       .ct_item_ops    = &package_appid_item_ops,
+       .ct_attrs       = package_appid_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+
+struct sdcardfs_packages {
+       struct config_group group;
+};
+
+static inline struct sdcardfs_packages *to_sdcardfs_packages(struct config_item *item)
+{
+       return item ? container_of(to_config_group(item), struct sdcardfs_packages, group) : NULL;
+}
+
+static struct config_item *sdcardfs_packages_make_item(struct config_group *group, const char *name)
+{
+       struct package_appid *package_appid;
+
+       package_appid = kzalloc(sizeof(struct package_appid), GFP_KERNEL);
+       if (!package_appid)
+               return ERR_PTR(-ENOMEM);
+
+       config_item_init_type_name(&package_appid->item, name,
+                                  &package_appid_type);
+
+       package_appid->add_pid = 0;
+
+       return &package_appid->item;
+}
+
+static ssize_t packages_attr_show(struct config_item *item,
+                                        char *page)
+{
+       struct hashtable_entry *hash_cur;
+       struct hlist_node *h_t;
+       int i;
+       int count = 0;
+       mutex_lock(&pkgl_data_all->hashtable_lock);
+       hash_for_each_safe(pkgl_data_all->package_to_appid, i, h_t, hash_cur, hlist)
+               count += snprintf(page + count, PAGE_SIZE - count, "%s %d\n", (char *)hash_cur->key, hash_cur->value);
+       mutex_unlock(&pkgl_data_all->hashtable_lock);
+
+
+       return count;
+}
+
+static struct configfs_attribute sdcardfs_packages_attr_description = {
+       .ca_owner = THIS_MODULE,
+       .ca_name = "packages_gid.list",
+       .ca_mode = S_IRUGO,
+       .show = packages_attr_show,
+};
+
+static struct configfs_attribute *sdcardfs_packages_attrs[] = {
+       &sdcardfs_packages_attr_description,
+       NULL,
+};
+
+static void sdcardfs_packages_release(struct config_item *item)
+{
+
+       printk(KERN_INFO "sdcardfs: destroyed something?\n");
+       kfree(to_sdcardfs_packages(item));
+}
+
+static struct configfs_item_operations sdcardfs_packages_item_ops = {
+       .release        = sdcardfs_packages_release,
+};
+
+/*
+ * Note that, since no extra work is required on ->drop_item(),
+ * no ->drop_item() is provided.
+ */
+static struct configfs_group_operations sdcardfs_packages_group_ops = {
+       .make_item      = sdcardfs_packages_make_item,
+};
+
+static struct config_item_type sdcardfs_packages_type = {
+       .ct_item_ops    = &sdcardfs_packages_item_ops,
+       .ct_group_ops   = &sdcardfs_packages_group_ops,
+       .ct_attrs       = sdcardfs_packages_attrs,
+       .ct_owner       = THIS_MODULE,
+};
+
+static struct configfs_subsystem sdcardfs_packages_subsys = {
+       .su_group = {
+               .cg_item = {
+                       .ci_namebuf = "sdcardfs",
+                       .ci_type = &sdcardfs_packages_type,
+               },
+       },
+};
+
+static int configfs_sdcardfs_init(void)
+{
+       int ret;
+       struct configfs_subsystem *subsys = &sdcardfs_packages_subsys;
+
+       config_group_init(&subsys->su_group);
+       mutex_init(&subsys->su_mutex);
+       ret = configfs_register_subsystem(subsys);
+       if (ret) {
+               printk(KERN_ERR "Error %d while registering subsystem %s\n",
+                      ret,
+                      subsys->su_group.cg_item.ci_namebuf);
+       }
+       return ret;
+}
+
+static void configfs_sdcardfs_exit(void)
+{
+       configfs_unregister_subsystem(&sdcardfs_packages_subsys);
+}
+
+int packagelist_init(void)
+{
+       hashtable_entry_cachep =
+               kmem_cache_create("packagelist_hashtable_entry",
+                                       sizeof(struct hashtable_entry), 0, 0, NULL);
+       if (!hashtable_entry_cachep) {
+               printk(KERN_ERR "sdcardfs: failed creating pkgl_hashtable entry slab cache\n");
+               return -ENOMEM;
+       }
+
+       pkgl_data_all = packagelist_create();
+       configfs_sdcardfs_init();
+        return 0;
+}
+
+void packagelist_exit(void)
+{
+       configfs_sdcardfs_exit();
+       packagelist_destroy(pkgl_data_all);
+       if (hashtable_entry_cachep)
+               kmem_cache_destroy(hashtable_entry_cachep);
+}
diff --git a/fs/sdcardfs/sdcardfs.h b/fs/sdcardfs/sdcardfs.h
new file mode 100644 (file)
index 0000000..f111f89
--- /dev/null
@@ -0,0 +1,530 @@
+/*
+ * fs/sdcardfs/sdcardfs.h
+ *
+ * The sdcardfs v2.0
+ *   This file system replaces the sdcard daemon on Android
+ *   On version 2.0, some of the daemon functions have been ported
+ *   to support the multi-user concepts of Android 4.4
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#ifndef _SDCARDFS_H_
+#define _SDCARDFS_H_
+
+#include <linux/dcache.h>
+#include <linux/file.h>
+#include <linux/fs.h>
+#include <linux/mm.h>
+#include <linux/mount.h>
+#include <linux/namei.h>
+#include <linux/seq_file.h>
+#include <linux/statfs.h>
+#include <linux/fs_stack.h>
+#include <linux/magic.h>
+#include <linux/uaccess.h>
+#include <linux/slab.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/security.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include "multiuser.h"
+
+/* the file system name */
+#define SDCARDFS_NAME "sdcardfs"
+
+/* sdcardfs root inode number */
+#define SDCARDFS_ROOT_INO     1
+
+/* useful for tracking code reachability */
+#define UDBG printk(KERN_DEFAULT "DBG:%s:%s:%d\n", __FILE__, __func__, __LINE__)
+
+#define SDCARDFS_DIRENT_SIZE 256
+
+/* temporary static uid settings for development */
+#define AID_ROOT             0 /* uid for accessing /mnt/sdcard & extSdcard */
+#define AID_MEDIA_RW      1023 /* internal media storage write access */
+
+#define AID_SDCARD_RW     1015 /* external storage write access */
+#define AID_SDCARD_R      1028 /* external storage read access */
+#define AID_SDCARD_PICS   1033 /* external storage photos access */
+#define AID_SDCARD_AV     1034 /* external storage audio/video access */
+#define AID_SDCARD_ALL    1035 /* access all users external storage */
+
+#define AID_PACKAGE_INFO  1027
+
+#define fix_derived_permission(x)      \
+       do {                                            \
+               (x)->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(x)->d_uid);    \
+               (x)->i_gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(x)));  \
+               (x)->i_mode = ((x)->i_mode & S_IFMT) | get_mode(SDCARDFS_I(x));\
+       } while (0)
+
+
+/* OVERRIDE_CRED() and REVERT_CRED()
+ *     OVERRID_CRED()
+ *             backup original task->cred
+ *             and modifies task->cred->fsuid/fsgid to specified value.
+ *     REVERT_CRED()
+ *             restore original task->cred->fsuid/fsgid.
+ * These two macro should be used in pair, and OVERRIDE_CRED() should be
+ * placed at the beginning of a function, right after variable declaration.
+ */
+#define OVERRIDE_CRED(sdcardfs_sbi, saved_cred)                \
+       saved_cred = override_fsids(sdcardfs_sbi);      \
+       if (!saved_cred) { return -ENOMEM; }
+
+#define OVERRIDE_CRED_PTR(sdcardfs_sbi, saved_cred)    \
+       saved_cred = override_fsids(sdcardfs_sbi);      \
+       if (!saved_cred) { return ERR_PTR(-ENOMEM); }
+
+#define REVERT_CRED(saved_cred)        revert_fsids(saved_cred)
+
+#define DEBUG_CRED()           \
+       printk("KAKJAGI: %s:%d fsuid %d fsgid %d\n",    \
+               __FUNCTION__, __LINE__,                 \
+               (int)current->cred->fsuid,              \
+               (int)current->cred->fsgid);
+
+/* Android 5.0 support */
+
+/* Permission mode for a specific node. Controls how file permissions
+ * are derived for children nodes. */
+typedef enum {
+    /* Nothing special; this node should just inherit from its parent. */
+    PERM_INHERIT,
+    /* This node is one level above a normal root; used for legacy layouts
+     * which use the first level to represent user_id. */
+    PERM_PRE_ROOT,
+    /* This node is "/" */
+    PERM_ROOT,
+    /* This node is "/Android" */
+    PERM_ANDROID,
+    /* This node is "/Android/data" */
+    PERM_ANDROID_DATA,
+    /* This node is "/Android/obb" */
+    PERM_ANDROID_OBB,
+    /* This node is "/Android/media" */
+    PERM_ANDROID_MEDIA,
+} perm_t;
+
+struct sdcardfs_sb_info;
+struct sdcardfs_mount_options;
+
+/* Do not directly use this function. Use OVERRIDE_CRED() instead. */
+const struct cred * override_fsids(struct sdcardfs_sb_info* sbi);
+/* Do not directly use this function, use REVERT_CRED() instead. */
+void revert_fsids(const struct cred * old_cred);
+
+/* operations vectors defined in specific files */
+extern const struct file_operations sdcardfs_main_fops;
+extern const struct file_operations sdcardfs_dir_fops;
+extern const struct inode_operations sdcardfs_main_iops;
+extern const struct inode_operations sdcardfs_dir_iops;
+extern const struct inode_operations sdcardfs_symlink_iops;
+extern const struct super_operations sdcardfs_sops;
+extern const struct dentry_operations sdcardfs_ci_dops;
+extern const struct address_space_operations sdcardfs_aops, sdcardfs_dummy_aops;
+extern const struct vm_operations_struct sdcardfs_vm_ops;
+
+extern int sdcardfs_init_inode_cache(void);
+extern void sdcardfs_destroy_inode_cache(void);
+extern int sdcardfs_init_dentry_cache(void);
+extern void sdcardfs_destroy_dentry_cache(void);
+extern int new_dentry_private_data(struct dentry *dentry);
+extern void free_dentry_private_data(struct dentry *dentry);
+extern struct dentry *sdcardfs_lookup(struct inode *dir, struct dentry *dentry,
+                               unsigned int flags);
+extern struct inode *sdcardfs_iget(struct super_block *sb,
+                                struct inode *lower_inode, userid_t id);
+extern int sdcardfs_interpose(struct dentry *dentry, struct super_block *sb,
+                           struct path *lower_path, userid_t id);
+
+/* file private data */
+struct sdcardfs_file_info {
+       struct file *lower_file;
+       const struct vm_operations_struct *lower_vm_ops;
+};
+
+/* sdcardfs inode data in memory */
+struct sdcardfs_inode_info {
+       struct inode *lower_inode;
+       /* state derived based on current position in hierachy */
+       perm_t perm;
+       userid_t userid;
+       uid_t d_uid;
+       bool under_android;
+
+       struct inode vfs_inode;
+};
+
+
+/* sdcardfs dentry data in memory */
+struct sdcardfs_dentry_info {
+       spinlock_t lock;        /* protects lower_path */
+       struct path lower_path;
+       struct path orig_path;
+};
+
+struct sdcardfs_mount_options {
+       uid_t fs_low_uid;
+       gid_t fs_low_gid;
+       userid_t fs_user_id;
+       gid_t gid;
+       mode_t mask;
+       bool multiuser;
+       unsigned int reserved_mb;
+};
+
+/* sdcardfs super-block data in memory */
+struct sdcardfs_sb_info {
+       struct super_block *sb;
+       struct super_block *lower_sb;
+       /* derived perm policy : some of options have been added
+        * to sdcardfs_mount_options (Android 4.4 support) */
+       struct sdcardfs_mount_options options;
+       spinlock_t lock;        /* protects obbpath */
+       char *obbpath_s;
+       struct path obbpath;
+       void *pkgl_id;
+       struct list_head list;
+};
+
+/*
+ * inode to private data
+ *
+ * Since we use containers and the struct inode is _inside_ the
+ * sdcardfs_inode_info structure, SDCARDFS_I will always (given a non-NULL
+ * inode pointer), return a valid non-NULL pointer.
+ */
+static inline struct sdcardfs_inode_info *SDCARDFS_I(const struct inode *inode)
+{
+       return container_of(inode, struct sdcardfs_inode_info, vfs_inode);
+}
+
+/* dentry to private data */
+#define SDCARDFS_D(dent) ((struct sdcardfs_dentry_info *)(dent)->d_fsdata)
+
+/* superblock to private data */
+#define SDCARDFS_SB(super) ((struct sdcardfs_sb_info *)(super)->s_fs_info)
+
+/* file to private Data */
+#define SDCARDFS_F(file) ((struct sdcardfs_file_info *)((file)->private_data))
+
+/* file to lower file */
+static inline struct file *sdcardfs_lower_file(const struct file *f)
+{
+       return SDCARDFS_F(f)->lower_file;
+}
+
+static inline void sdcardfs_set_lower_file(struct file *f, struct file *val)
+{
+       SDCARDFS_F(f)->lower_file = val;
+}
+
+/* inode to lower inode. */
+static inline struct inode *sdcardfs_lower_inode(const struct inode *i)
+{
+       return SDCARDFS_I(i)->lower_inode;
+}
+
+static inline void sdcardfs_set_lower_inode(struct inode *i, struct inode *val)
+{
+       SDCARDFS_I(i)->lower_inode = val;
+}
+
+/* superblock to lower superblock */
+static inline struct super_block *sdcardfs_lower_super(
+       const struct super_block *sb)
+{
+       return SDCARDFS_SB(sb)->lower_sb;
+}
+
+static inline void sdcardfs_set_lower_super(struct super_block *sb,
+                                         struct super_block *val)
+{
+       SDCARDFS_SB(sb)->lower_sb = val;
+}
+
+/* path based (dentry/mnt) macros */
+static inline void pathcpy(struct path *dst, const struct path *src)
+{
+       dst->dentry = src->dentry;
+       dst->mnt = src->mnt;
+}
+
+/* sdcardfs_get_pname functions calls path_get()
+ * therefore, the caller must call "proper" path_put functions
+ */
+#define SDCARDFS_DENT_FUNC(pname) \
+static inline void sdcardfs_get_##pname(const struct dentry *dent, \
+                                       struct path *pname) \
+{ \
+       spin_lock(&SDCARDFS_D(dent)->lock); \
+       pathcpy(pname, &SDCARDFS_D(dent)->pname); \
+       path_get(pname); \
+       spin_unlock(&SDCARDFS_D(dent)->lock); \
+       return; \
+} \
+static inline void sdcardfs_put_##pname(const struct dentry *dent, \
+                                       struct path *pname) \
+{ \
+       path_put(pname); \
+       return; \
+} \
+static inline void sdcardfs_set_##pname(const struct dentry *dent, \
+                                       struct path *pname) \
+{ \
+       spin_lock(&SDCARDFS_D(dent)->lock); \
+       pathcpy(&SDCARDFS_D(dent)->pname, pname); \
+       spin_unlock(&SDCARDFS_D(dent)->lock); \
+       return; \
+} \
+static inline void sdcardfs_reset_##pname(const struct dentry *dent) \
+{ \
+       spin_lock(&SDCARDFS_D(dent)->lock); \
+       SDCARDFS_D(dent)->pname.dentry = NULL; \
+       SDCARDFS_D(dent)->pname.mnt = NULL; \
+       spin_unlock(&SDCARDFS_D(dent)->lock); \
+       return; \
+} \
+static inline void sdcardfs_put_reset_##pname(const struct dentry *dent) \
+{ \
+       struct path pname; \
+       spin_lock(&SDCARDFS_D(dent)->lock); \
+       if(SDCARDFS_D(dent)->pname.dentry) { \
+               pathcpy(&pname, &SDCARDFS_D(dent)->pname); \
+               SDCARDFS_D(dent)->pname.dentry = NULL; \
+               SDCARDFS_D(dent)->pname.mnt = NULL; \
+               spin_unlock(&SDCARDFS_D(dent)->lock); \
+               path_put(&pname); \
+       } else \
+               spin_unlock(&SDCARDFS_D(dent)->lock); \
+       return; \
+}
+
+SDCARDFS_DENT_FUNC(lower_path)
+SDCARDFS_DENT_FUNC(orig_path)
+
+static inline int get_gid(struct sdcardfs_inode_info *info) {
+       struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb);
+       if (sb_info->options.gid == AID_SDCARD_RW) {
+               /* As an optimization, certain trusted system components only run
+                * as owner but operate across all users. Since we're now handing
+                * out the sdcard_rw GID only to trusted apps, we're okay relaxing
+                * the user boundary enforcement for the default view. The UIDs
+                * assigned to app directories are still multiuser aware. */
+               return AID_SDCARD_RW;
+       } else {
+               return multiuser_get_uid(info->userid, sb_info->options.gid);
+       }
+}
+static inline int get_mode(struct sdcardfs_inode_info *info) {
+       int owner_mode;
+       int filtered_mode;
+       struct sdcardfs_sb_info *sb_info = SDCARDFS_SB(info->vfs_inode.i_sb);
+       int visible_mode = 0775 & ~sb_info->options.mask;
+
+       if (info->perm == PERM_PRE_ROOT) {
+               /* Top of multi-user view should always be visible to ensure
+               * secondary users can traverse inside. */
+               visible_mode = 0711;
+       } else if (info->under_android) {
+               /* Block "other" access to Android directories, since only apps
+               * belonging to a specific user should be in there; we still
+               * leave +x open for the default view. */
+               if (sb_info->options.gid == AID_SDCARD_RW) {
+                       visible_mode = visible_mode & ~0006;
+               } else {
+                       visible_mode = visible_mode & ~0007;
+               }
+       }
+       owner_mode = info->lower_inode->i_mode & 0700;
+       filtered_mode = visible_mode & (owner_mode | (owner_mode >> 3) | (owner_mode >> 6));
+       return filtered_mode;
+}
+
+static inline int has_graft_path(const struct dentry *dent)
+{
+       int ret = 0;
+
+       spin_lock(&SDCARDFS_D(dent)->lock);
+       if (SDCARDFS_D(dent)->orig_path.dentry != NULL)
+               ret = 1;
+       spin_unlock(&SDCARDFS_D(dent)->lock);
+
+       return ret;
+}
+
+static inline void sdcardfs_get_real_lower(const struct dentry *dent,
+                                               struct path *real_lower)
+{
+       /* in case of a local obb dentry
+        * the orig_path should be returned
+        */
+       if(has_graft_path(dent))
+               sdcardfs_get_orig_path(dent, real_lower);
+       else
+               sdcardfs_get_lower_path(dent, real_lower);
+}
+
+static inline void sdcardfs_put_real_lower(const struct dentry *dent,
+                                               struct path *real_lower)
+{
+       if(has_graft_path(dent))
+               sdcardfs_put_orig_path(dent, real_lower);
+       else
+               sdcardfs_put_lower_path(dent, real_lower);
+}
+
+extern struct mutex sdcardfs_super_list_lock;
+extern struct list_head sdcardfs_super_list;
+
+/* for packagelist.c */
+extern appid_t get_appid(void *pkgl_id, const char *app_name);
+extern int check_caller_access_to_name(struct inode *parent_node, const char* name);
+extern int open_flags_to_access_mode(int open_flags);
+extern int packagelist_init(void);
+extern void packagelist_exit(void);
+
+/* for derived_perm.c */
+extern void setup_derived_state(struct inode *inode, perm_t perm,
+                       userid_t userid, uid_t uid, bool under_android);
+extern void get_derived_permission(struct dentry *parent, struct dentry *dentry);
+extern void get_derived_permission_new(struct dentry *parent, struct dentry *dentry, struct dentry *newdentry);
+extern void get_derive_permissions_recursive(struct dentry *parent);
+
+extern void update_derived_permission_lock(struct dentry *dentry);
+extern int need_graft_path(struct dentry *dentry);
+extern int is_base_obbpath(struct dentry *dentry);
+extern int is_obbpath_invalid(struct dentry *dentry);
+extern int setup_obb_dentry(struct dentry *dentry, struct path *lower_path);
+
+/* locking helpers */
+static inline struct dentry *lock_parent(struct dentry *dentry)
+{
+       struct dentry *dir = dget_parent(dentry);
+       mutex_lock_nested(&d_inode(dir)->i_mutex, I_MUTEX_PARENT);
+       return dir;
+}
+
+static inline void unlock_dir(struct dentry *dir)
+{
+       mutex_unlock(&d_inode(dir)->i_mutex);
+       dput(dir);
+}
+
+static inline int prepare_dir(const char *path_s, uid_t uid, gid_t gid, mode_t mode)
+{
+       int err;
+       struct dentry *dent;
+       struct iattr attrs;
+       struct path parent;
+
+       dent = kern_path_locked(path_s, &parent);
+       if (IS_ERR(dent)) {
+               err = PTR_ERR(dent);
+               if (err == -EEXIST)
+                       err = 0;
+               goto out_unlock;
+       }
+
+       err = vfs_mkdir(d_inode(parent.dentry), dent, mode);
+       if (err) {
+               if (err == -EEXIST)
+                       err = 0;
+               goto out_dput;
+       }
+
+       attrs.ia_uid = make_kuid(&init_user_ns, uid);
+       attrs.ia_gid = make_kgid(&init_user_ns, gid);
+       attrs.ia_valid = ATTR_UID | ATTR_GID;
+       mutex_lock(&d_inode(dent)->i_mutex);
+       notify_change(dent, &attrs, NULL);
+       mutex_unlock(&d_inode(dent)->i_mutex);
+
+out_dput:
+       dput(dent);
+
+out_unlock:
+       /* parent dentry locked by lookup_create */
+       mutex_unlock(&d_inode(parent.dentry)->i_mutex);
+       path_put(&parent);
+       return err;
+}
+
+/*
+ * Return 1, if a disk has enough free space, otherwise 0.
+ * We assume that any files can not be overwritten.
+ */
+static inline int check_min_free_space(struct dentry *dentry, size_t size, int dir)
+{
+       int err;
+       struct path lower_path;
+       struct kstatfs statfs;
+       u64 avail;
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+
+       if (sbi->options.reserved_mb) {
+               /* Get fs stat of lower filesystem. */
+               sdcardfs_get_lower_path(dentry, &lower_path);
+               err = vfs_statfs(&lower_path, &statfs);
+               sdcardfs_put_lower_path(dentry, &lower_path);
+
+               if (unlikely(err))
+                       return 0;
+
+               /* Invalid statfs informations. */
+               if (unlikely(statfs.f_bsize == 0))
+                       return 0;
+
+               /* if you are checking directory, set size to f_bsize. */
+               if (unlikely(dir))
+                       size = statfs.f_bsize;
+
+               /* available size */
+               avail = statfs.f_bavail * statfs.f_bsize;
+
+               /* not enough space */
+               if ((u64)size > avail)
+                       return 0;
+
+               /* enough space */
+               if ((avail - size) > (sbi->options.reserved_mb * 1024 * 1024))
+                       return 1;
+
+               return 0;
+       } else
+               return 1;
+}
+
+/* Copies attrs and maintains sdcardfs managed attrs */
+static inline void sdcardfs_copy_and_fix_attrs(struct inode *dest, const struct inode *src)
+{
+       dest->i_mode = (src->i_mode  & S_IFMT) | get_mode(SDCARDFS_I(dest));
+       dest->i_uid = make_kuid(&init_user_ns, SDCARDFS_I(dest)->d_uid);
+       dest->i_gid = make_kgid(&init_user_ns, get_gid(SDCARDFS_I(dest)));
+       dest->i_rdev = src->i_rdev;
+       dest->i_atime = src->i_atime;
+       dest->i_mtime = src->i_mtime;
+       dest->i_ctime = src->i_ctime;
+       dest->i_blkbits = src->i_blkbits;
+       dest->i_flags = src->i_flags;
+       set_nlink(dest, src->i_nlink);
+}
+#endif /* not _SDCARDFS_H_ */
diff --git a/fs/sdcardfs/super.c b/fs/sdcardfs/super.c
new file mode 100644 (file)
index 0000000..1d64901
--- /dev/null
@@ -0,0 +1,222 @@
+/*
+ * fs/sdcardfs/super.c
+ *
+ * Copyright (c) 2013 Samsung Electronics Co. Ltd
+ *   Authors: Daeho Jeong, Woojoong Lee, Seunghwan Hyun,
+ *               Sunghwan Yun, Sungjong Seo
+ *
+ * This program has been developed as a stackable file system based on
+ * the WrapFS which written by
+ *
+ * Copyright (c) 1998-2011 Erez Zadok
+ * Copyright (c) 2009     Shrikar Archak
+ * Copyright (c) 2003-2011 Stony Brook University
+ * Copyright (c) 2003-2011 The Research Foundation of SUNY
+ *
+ * This file is dual licensed.  It may be redistributed and/or modified
+ * under the terms of the Apache 2.0 License OR version 2 of the GNU
+ * General Public License.
+ */
+
+#include "sdcardfs.h"
+
+/*
+ * The inode cache is used with alloc_inode for both our inode info and the
+ * vfs inode.
+ */
+static struct kmem_cache *sdcardfs_inode_cachep;
+
+/* final actions when unmounting a file system */
+static void sdcardfs_put_super(struct super_block *sb)
+{
+       struct sdcardfs_sb_info *spd;
+       struct super_block *s;
+
+       spd = SDCARDFS_SB(sb);
+       if (!spd)
+               return;
+
+       if(spd->obbpath_s) {
+               kfree(spd->obbpath_s);
+               path_put(&spd->obbpath);
+       }
+
+       /* decrement lower super references */
+       s = sdcardfs_lower_super(sb);
+       sdcardfs_set_lower_super(sb, NULL);
+       atomic_dec(&s->s_active);
+
+       kfree(spd);
+       sb->s_fs_info = NULL;
+}
+
+static int sdcardfs_statfs(struct dentry *dentry, struct kstatfs *buf)
+{
+       int err;
+       struct path lower_path;
+       u32 min_blocks;
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(dentry->d_sb);
+
+       sdcardfs_get_lower_path(dentry, &lower_path);
+       err = vfs_statfs(&lower_path, buf);
+       sdcardfs_put_lower_path(dentry, &lower_path);
+
+       if (sbi->options.reserved_mb) {
+               /* Invalid statfs informations. */
+               if (buf->f_bsize == 0) {
+                       printk(KERN_ERR "Returned block size is zero.\n");
+                       return -EINVAL;
+               }
+
+               min_blocks = ((sbi->options.reserved_mb * 1024 * 1024)/buf->f_bsize);
+               buf->f_blocks -= min_blocks;
+
+               if (buf->f_bavail > min_blocks)
+                       buf->f_bavail -= min_blocks;
+               else
+                       buf->f_bavail = 0;
+
+               /* Make reserved blocks invisiable to media storage */
+               buf->f_bfree = buf->f_bavail;
+       }
+
+       /* set return buf to our f/s to avoid confusing user-level utils */
+       buf->f_type = SDCARDFS_SUPER_MAGIC;
+
+       return err;
+}
+
+/*
+ * @flags: numeric mount options
+ * @options: mount options string
+ */
+static int sdcardfs_remount_fs(struct super_block *sb, int *flags, char *options)
+{
+       int err = 0;
+
+       /*
+        * The VFS will take care of "ro" and "rw" flags among others.  We
+        * can safely accept a few flags (RDONLY, MANDLOCK), and honor
+        * SILENT, but anything else left over is an error.
+        */
+       if ((*flags & ~(MS_RDONLY | MS_MANDLOCK | MS_SILENT)) != 0) {
+               printk(KERN_ERR
+                      "sdcardfs: remount flags 0x%x unsupported\n", *flags);
+               err = -EINVAL;
+       }
+
+       return err;
+}
+
+/*
+ * Called by iput() when the inode reference count reached zero
+ * and the inode is not hashed anywhere.  Used to clear anything
+ * that needs to be, before the inode is completely destroyed and put
+ * on the inode free list.
+ */
+static void sdcardfs_evict_inode(struct inode *inode)
+{
+       struct inode *lower_inode;
+
+       truncate_inode_pages(&inode->i_data, 0);
+       clear_inode(inode);
+       /*
+        * Decrement a reference to a lower_inode, which was incremented
+        * by our read_inode when it was created initially.
+        */
+       lower_inode = sdcardfs_lower_inode(inode);
+       sdcardfs_set_lower_inode(inode, NULL);
+       iput(lower_inode);
+}
+
+static struct inode *sdcardfs_alloc_inode(struct super_block *sb)
+{
+       struct sdcardfs_inode_info *i;
+
+       i = kmem_cache_alloc(sdcardfs_inode_cachep, GFP_KERNEL);
+       if (!i)
+               return NULL;
+
+       /* memset everything up to the inode to 0 */
+       memset(i, 0, offsetof(struct sdcardfs_inode_info, vfs_inode));
+
+       i->vfs_inode.i_version = 1;
+       return &i->vfs_inode;
+}
+
+static void sdcardfs_destroy_inode(struct inode *inode)
+{
+       kmem_cache_free(sdcardfs_inode_cachep, SDCARDFS_I(inode));
+}
+
+/* sdcardfs inode cache constructor */
+static void init_once(void *obj)
+{
+       struct sdcardfs_inode_info *i = obj;
+
+       inode_init_once(&i->vfs_inode);
+}
+
+int sdcardfs_init_inode_cache(void)
+{
+       int err = 0;
+
+       sdcardfs_inode_cachep =
+               kmem_cache_create("sdcardfs_inode_cache",
+                                 sizeof(struct sdcardfs_inode_info), 0,
+                                 SLAB_RECLAIM_ACCOUNT, init_once);
+       if (!sdcardfs_inode_cachep)
+               err = -ENOMEM;
+       return err;
+}
+
+/* sdcardfs inode cache destructor */
+void sdcardfs_destroy_inode_cache(void)
+{
+       if (sdcardfs_inode_cachep)
+               kmem_cache_destroy(sdcardfs_inode_cachep);
+}
+
+/*
+ * Used only in nfs, to kill any pending RPC tasks, so that subsequent
+ * code can actually succeed and won't leave tasks that need handling.
+ */
+static void sdcardfs_umount_begin(struct super_block *sb)
+{
+       struct super_block *lower_sb;
+
+       lower_sb = sdcardfs_lower_super(sb);
+       if (lower_sb && lower_sb->s_op && lower_sb->s_op->umount_begin)
+               lower_sb->s_op->umount_begin(lower_sb);
+}
+
+static int sdcardfs_show_options(struct seq_file *m, struct dentry *root)
+{
+       struct sdcardfs_sb_info *sbi = SDCARDFS_SB(root->d_sb);
+       struct sdcardfs_mount_options *opts = &sbi->options;
+
+       if (opts->fs_low_uid != 0)
+               seq_printf(m, ",uid=%u", opts->fs_low_uid);
+       if (opts->fs_low_gid != 0)
+               seq_printf(m, ",gid=%u", opts->fs_low_gid);
+
+       if (opts->multiuser)
+               seq_printf(m, ",multiuser");
+
+       if (opts->reserved_mb != 0)
+               seq_printf(m, ",reserved=%uMB", opts->reserved_mb);
+
+       return 0;
+};
+
+const struct super_operations sdcardfs_sops = {
+       .put_super      = sdcardfs_put_super,
+       .statfs         = sdcardfs_statfs,
+       .remount_fs     = sdcardfs_remount_fs,
+       .evict_inode    = sdcardfs_evict_inode,
+       .umount_begin   = sdcardfs_umount_begin,
+       .show_options   = sdcardfs_show_options,
+       .alloc_inode    = sdcardfs_alloc_inode,
+       .destroy_inode  = sdcardfs_destroy_inode,
+       .drop_inode     = generic_delete_inode,
+};
index 8a2e009c8a5a9503aa4c31815e1057092ec6076f..e7041ec48af8557c26dc3113fc7c9b853668e897 100644 (file)
@@ -161,6 +161,7 @@ struct dentry_operations {
        struct vfsmount *(*d_automount)(struct path *);
        int (*d_manage)(struct dentry *, bool);
        struct inode *(*d_select_inode)(struct dentry *, unsigned);
+       void (*d_canonical_path)(const struct dentry *, struct path *);
 } ____cacheline_aligned;
 
 /*
index d8c6334cd15005c16162f57959e20b2e09f99d03..d53c25453aca084e9b0390473323ac9897961167 100644 (file)
@@ -75,6 +75,8 @@ extern struct dentry *user_path_create(int, const char __user *, struct path *,
 extern void done_path_create(struct path *, struct dentry *);
 extern struct dentry *kern_path_locked(const char *, struct path *);
 extern int kern_path_mountpoint(int, const char *, struct path *, unsigned int);
+extern int vfs_path_lookup(struct dentry *, struct vfsmount *,
+               const char *, unsigned int, struct path *);
 
 extern struct dentry *lookup_one_len(const char *, struct dentry *, int);
 
index a75840c1aa71414acc43468da6cc8f83ec06c1b8..9c29122037f95283cc02b8af995975e80e059abd 100644 (file)
@@ -34,6 +34,7 @@ extern const struct file_operations random_fops, urandom_fops;
 #endif
 
 unsigned int get_random_int(void);
+unsigned long get_random_long(void);
 unsigned long randomize_range(unsigned long start, unsigned long end, unsigned long len);
 
 u32 prandom_u32(void);
index ad8b76936c7fb70e35f69e4e7327d41d0d7ac8ba..d84d8c301546bb14724ad858b209cebde035cd8d 100644 (file)
 #define MAX_SUSPEND_ABORT_LEN 256
 
 void log_wakeup_reason(int irq);
-void log_suspend_abort_reason(const char *fmt, ...);
 int check_wakeup_reason(int irq);
 
+#ifdef CONFIG_SUSPEND
+void log_suspend_abort_reason(const char *fmt, ...);
+#else
+static inline void log_suspend_abort_reason(const char *fmt, ...) { }
+#endif
+
 #endif /* _LINUX_WAKEUP_REASON_H */
index de77035567c45fbd262f7a002a96c6ea2001100e..9af0d898016a611135753b4a14c04906bf13fc71 100644 (file)
@@ -135,7 +135,7 @@ TRACE_EVENT(cpu_frequency_limits,
 
        TP_fast_assign(
                __entry->min_freq = min_freq;
-               __entry->max_freq = min_freq;
+               __entry->max_freq = max_freq;
                __entry->cpu_id = cpu_id;
        ),
 
index accb036bbc9c3621d9929dda225b6d0689348860..cfb5c406f34466b487ffaf5bff4d8b5bd6f172ec 100644 (file)
@@ -52,6 +52,8 @@
 #define REISER2FS_SUPER_MAGIC_STRING   "ReIsEr2Fs"
 #define REISER2FS_JR_SUPER_MAGIC_STRING        "ReIsEr3Fs"
 
+#define SDCARDFS_SUPER_MAGIC   0xb550ca10
+
 #define SMB_SUPER_MAGIC                0x517B
 #define CGROUP_SUPER_MAGIC     0x27e0eb
 
index f76ea56f8dfff2a2a3fe6bd59e5fdba3b2b3a1ea..2098f7d5fd9e91b905635b989d19d8af74e02a6f 100644 (file)
@@ -1,6 +1,7 @@
 config SUSPEND
        bool "Suspend to RAM and standby"
        depends on ARCH_SUSPEND_POSSIBLE
+       select RTC_LIB
        default y
        ---help---
          Allow the system to enter sleep states in which main memory is