diff --git a/drivers/ddk/Makefile b/drivers/ddk/Makefile index f341d978ed..b25edd232a 100644 --- a/drivers/ddk/Makefile +++ b/drivers/ddk/Makefile @@ -12,6 +12,7 @@ INCLUDES = -I$(DRV_INCLUDES) \ DEFINES = -DKOLIBRI -D__KERNEL__ -DCONFIG_X86_32 -DCONFIG_DMI -DCONFIG_TINY_RCU DEFINES+= -DCONFIG_X86_L1_CACHE_SHIFT=6 -DCONFIG_ARCH_HAS_CACHE_LINE_SIZE +DEFINES+= -DCONFIG_PRINTK CFLAGS = -c -Os $(INCLUDES) $(DEFINES) -march=i686 -fomit-frame-pointer -fno-builtin-printf \ -mno-stack-arg-probe -mpreferred-stack-boundary=2 -mincoming-stack-boundary=2 -fno-ident diff --git a/drivers/ddk/linux/scatterlist.c b/drivers/ddk/linux/scatterlist.c index af76daf2a2..547777bf20 100644 --- a/drivers/ddk/linux/scatterlist.c +++ b/drivers/ddk/linux/scatterlist.c @@ -349,8 +349,69 @@ int sg_alloc_table(struct sg_table *table, unsigned int nents, gfp_t gfp_mask) } EXPORT_SYMBOL(sg_alloc_table); +/** + * sg_alloc_table_from_pages - Allocate and initialize an sg table from + * an array of pages + * @sgt: The sg table header to use + * @pages: Pointer to an array of page pointers + * @n_pages: Number of pages in the pages array + * @offset: Offset from start of the first page to the start of a buffer + * @size: Number of valid bytes in the buffer (after offset) + * @gfp_mask: GFP allocation mask + * + * Description: + * Allocate and initialize an sg table from a list of pages. Contiguous + * ranges of the pages are squashed into a single scatterlist node. A user + * may provide an offset at a start and a size of valid data in a buffer + * specified by the page array. The returned sg table is released by + * sg_free_table. + * + * Returns: + * 0 on success, negative error on failure + */ +int sg_alloc_table_from_pages(struct sg_table *sgt, + struct page **pages, unsigned int n_pages, + unsigned long offset, unsigned long size, + gfp_t gfp_mask) +{ + unsigned int chunks; + unsigned int i; + unsigned int cur_page; + int ret; + struct scatterlist *s; + /* compute number of contiguous chunks */ + chunks = 1; + for (i = 1; i < n_pages; ++i) + if (page_to_pfn(pages[i]) != page_to_pfn(pages[i - 1]) + 1) + ++chunks; + ret = sg_alloc_table(sgt, chunks, gfp_mask); + if (unlikely(ret)) + return ret; + + /* merging chunks and putting them into the scatterlist */ + cur_page = 0; + for_each_sg(sgt->sgl, s, sgt->orig_nents, i) { + unsigned long chunk_size; + unsigned int j; + + /* look for the end of the current chunk */ + for (j = cur_page + 1; j < n_pages; ++j) + if (page_to_pfn(pages[j]) != + page_to_pfn(pages[j - 1]) + 1) + break; + + chunk_size = ((j - cur_page) << PAGE_SHIFT) - offset; + sg_set_page(s, pages[cur_page], min(size, chunk_size), offset); + size -= chunk_size; + offset = 0; + cur_page = j; + } + + return 0; +} +EXPORT_SYMBOL(sg_alloc_table_from_pages); void __sg_page_iter_start(struct sg_page_iter *piter, struct scatterlist *sglist, unsigned int nents, diff --git a/drivers/ddk/stdio/vsprintf.c b/drivers/ddk/stdio/vsprintf.c index 2ecc279f5b..d1ef0e0399 100644 --- a/drivers/ddk/stdio/vsprintf.c +++ b/drivers/ddk/stdio/vsprintf.c @@ -41,8 +41,7 @@ #define KSTRTOX_OVERFLOW (1U << 31) -const char hex_asc[] = "0123456789abcdef"; -const char hex_asc_upper[] = "0123456789ABCDEF"; + /* Works only for digits and letters, but small and fast */ #define TOLOWER(x) ((x) | 0x20) @@ -1080,6 +1079,8 @@ int kptr_restrict = 1; * (legacy clock framework) of the clock * - 'Cr' For a clock, it prints the current rate of the clock * + * ** Please update also Documentation/printk-formats.txt when making changes ** + * * Note: The difference between 'S' and 'F' is that on ia64 and ppc64 * function pointers are really function descriptors, which contain a * pointer to the real address. @@ -1088,7 +1089,7 @@ static noinline_for_stack char *pointer(const char *fmt, char *buf, char *end, void *ptr, struct printf_spec spec) { - int default_width = 2 * sizeof(void *) + (spec.flags & SPECIAL ? 2 : 0); + const int default_width = 2 * sizeof(void *); if (!ptr && *fmt != 'K') { /* @@ -1315,11 +1316,10 @@ qualifier: case 'n': /* - * Since %n poses a greater security risk than utility, treat - * it as an invalid format specifier. Warn about its use so - * that new instances don't get added. + * Since %n poses a greater security risk than + * utility, treat it as any other invalid or + * unsupported format specifier. */ -// WARN_ONCE(1, "Please remove ignored %%n in '%s'\n", fmt); /* Fall-through */ default: @@ -1357,41 +1357,16 @@ qualifier: * @fmt: The format string to use * @args: Arguments for the format string * - * This function follows C99 vsnprintf, but has some extensions: - * %pS output the name of a text symbol with offset - * %ps output the name of a text symbol without offset - * %pF output the name of a function pointer with its offset - * %pf output the name of a function pointer without its offset - * %pB output the name of a backtrace symbol with its offset - * %pR output the address range in a struct resource with decoded flags - * %pr output the address range in a struct resource with raw flags - * %pb output the bitmap with field width as the number of bits - * %pbl output the bitmap as range list with field width as the number of bits - * %pM output a 6-byte MAC address with colons - * %pMR output a 6-byte MAC address with colons in reversed order - * %pMF output a 6-byte MAC address with dashes - * %pm output a 6-byte MAC address without colons - * %pmR output a 6-byte MAC address without colons in reversed order - * %pI4 print an IPv4 address without leading zeros - * %pi4 print an IPv4 address with leading zeros - * %pI6 print an IPv6 address with colons - * %pi6 print an IPv6 address without colons - * %pI6c print an IPv6 address as specified by RFC 5952 - * %pIS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address - * %piS depending on sa_family of 'struct sockaddr *' print IPv4/IPv6 address - * %pU[bBlL] print a UUID/GUID in big or little endian using lower or upper - * case. - * %*pE[achnops] print an escaped buffer - * %*ph[CDN] a variable-length hex string with a separator (supports up to 64 - * bytes of the input) - * %pC output the name (Common Clock Framework) or address (legacy clock - * framework) of a clock - * %pCn output the name (Common Clock Framework) or address (legacy clock - * framework) of a clock - * %pCr output the current rate of a clock - * %n is ignored + * This function generally follows C99 vsnprintf, but has some + * extensions and a few limitations: * - * ** Please update Documentation/printk-formats.txt when making changes ** + * %n is unsupported + * %p* is handled by pointer() + * + * See pointer() or Documentation/printk-formats.txt for more + * extensive description. + * + * ** Please update the documentation in both places when making changes ** * * The return value is the number of characters which would * be generated for the given input, excluding the trailing @@ -1490,10 +1465,15 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) break; case FORMAT_TYPE_INVALID: - if (str < end) - *str = '%'; - ++str; - break; + /* + * Presumably the arguments passed gcc's type + * checking, but there is no safe or sane way + * for us to continue parsing the format and + * fetching from the va_list; the remaining + * specifiers and arguments would be out of + * sync. + */ + goto out; default: switch (spec.type) { @@ -1538,6 +1518,7 @@ int vsnprintf(char *buf, size_t size, const char *fmt, va_list args) } } +out: if (size > 0) { if (str < end) *str = '\0'; diff --git a/drivers/include/linux/dma-buf.h b/drivers/include/linux/dma-buf.h index f8658833ca..6772b0159f 100644 --- a/drivers/include/linux/dma-buf.h +++ b/drivers/include/linux/dma-buf.h @@ -153,6 +153,36 @@ struct dma_buf_attachment { void *priv; }; +/** + * struct dma_buf_export_info - holds information needed to export a dma_buf + * @exp_name: name of the exporter - useful for debugging. + * @owner: pointer to exporter module - used for refcounting kernel module + * @ops: Attach allocator-defined dma buf ops to the new buffer + * @size: Size of the buffer + * @flags: mode flags for the file + * @resv: reservation-object, NULL to allocate default one + * @priv: Attach private data of allocator to this buffer + * + * This structure holds the information required to export the buffer. Used + * with dma_buf_export() only. + */ +struct dma_buf_export_info { + const char *exp_name; + struct module *owner; + const struct dma_buf_ops *ops; + size_t size; + int flags; + struct reservation_object *resv; + void *priv; +}; + +/** + * helper macro for exporters; zeros and fills in most common values + */ +#define DEFINE_DMA_BUF_EXPORT_INFO(a) \ + struct dma_buf_export_info a = { .exp_name = KBUILD_MODNAME, \ + .owner = THIS_MODULE } + /** * get_dma_buf - convenience wrapper for get_file. * @dmabuf: [in] pointer to dma_buf diff --git a/drivers/include/linux/file.h b/drivers/include/linux/file.h index b12e460411..3cda365f66 100644 --- a/drivers/include/linux/file.h +++ b/drivers/include/linux/file.h @@ -4,5 +4,12 @@ #ifndef __LINUX_FILE_H #define __LINUX_FILE_H + +#include +#include +#include + struct file; +extern void fput(struct file *); +extern struct file *fget(unsigned int fd); #endif /* __LINUX_FILE_H */ diff --git a/drivers/include/linux/fs.h b/drivers/include/linux/fs.h index 5f29708e5e..3bde2bc893 100644 --- a/drivers/include/linux/fs.h +++ b/drivers/include/linux/fs.h @@ -1,3 +1,97 @@ #ifndef _LINUX_FS_H #define _LINUX_FS_H +#include +#include +#include +#include +#define MAY_EXEC 0x00000001 +#define MAY_WRITE 0x00000002 +#define MAY_READ 0x00000004 +#define MAY_APPEND 0x00000008 +#define MAY_ACCESS 0x00000010 +#define MAY_OPEN 0x00000020 +#define MAY_CHDIR 0x00000040 +/* called from RCU mode, don't block */ +#define MAY_NOT_BLOCK 0x00000080 +/* + * Attribute flags. These should be or-ed together to figure out what + * has been changed! + */ +#define ATTR_MODE (1 << 0) +#define ATTR_UID (1 << 1) +#define ATTR_GID (1 << 2) +#define ATTR_SIZE (1 << 3) +#define ATTR_ATIME (1 << 4) +#define ATTR_MTIME (1 << 5) +#define ATTR_CTIME (1 << 6) +#define ATTR_ATIME_SET (1 << 7) +#define ATTR_MTIME_SET (1 << 8) +#define ATTR_FORCE (1 << 9) /* Not a change, but a change it */ +#define ATTR_ATTR_FLAG (1 << 10) +#define ATTR_KILL_SUID (1 << 11) +#define ATTR_KILL_SGID (1 << 12) +#define ATTR_FILE (1 << 13) +#define ATTR_KILL_PRIV (1 << 14) +#define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ +#define ATTR_TIMES_SET (1 << 16) +/* + * inode->i_mutex nesting subclasses for the lock validator: + * + * 0: the object of the current VFS operation + * 1: parent + * 2: child/target + * 3: xattr + * 4: second non-directory + * 5: second parent (when locking independent directories in rename) + * + * I_MUTEX_NONDIR2 is for certain operations (such as rename) which lock two + * non-directories at once. + * + * The locking order between these classes is + * parent[2] -> child -> grandchild -> normal -> xattr -> second non-directory + */ +enum inode_i_mutex_lock_class +{ + I_MUTEX_NORMAL, + I_MUTEX_PARENT, + I_MUTEX_CHILD, + I_MUTEX_XATTR, + I_MUTEX_NONDIR2, + I_MUTEX_PARENT2, +}; +struct file { + + /* + * Protects f_ep_links, f_flags. + * Must not be taken from IRQ context. + */ + spinlock_t f_lock; + atomic_long_t f_count; + unsigned int f_flags; + fmode_t f_mode; + + /* needed for tty driver, and maybe others */ + void *private_data; + + struct page **pages; /* physical memory backend */ + unsigned int count; + unsigned int allocated; + void *vma; + +} __attribute__((aligned(4))); /* lest something weird decides that 2 is OK */ +#define get_file_rcu(x) atomic_long_inc_not_zero(&(x)->f_count) +#define fput_atomic(x) atomic_long_add_unless(&(x)->f_count, -1, 1) +#define file_count(x) atomic_long_read(&(x)->f_count) +#define FL_POSIX 1 +#define FL_FLOCK 2 +#define FL_DELEG 4 /* NFSv4 delegation */ +#define FL_ACCESS 8 /* not trying to lock, just looking */ +#define FL_EXISTS 16 /* when unlocking, test for existence */ +#define FL_LEASE 32 /* lease held on this file */ +#define FL_CLOSE 64 /* unlock on close */ +#define FL_SLEEP 128 /* A blocking lock */ +#define FL_DOWNGRADE_PENDING 256 /* Lease is being downgraded */ +#define FL_UNLOCK_PENDING 512 /* Lease is being broken */ +#define FL_OFDLCK 1024 /* lock is "owned" by struct file */ +#define FL_LAYOUT 2048 /* outstanding pNFS layout */ #endif /* _LINUX_FS_H */ diff --git a/drivers/include/linux/kernel.h b/drivers/include/linux/kernel.h index ebc098c30e..cdc0b515cf 100644 --- a/drivers/include/linux/kernel.h +++ b/drivers/include/linux/kernel.h @@ -684,14 +684,6 @@ typedef union u64 raw; }evhandle_t; -struct file -{ - struct page **pages; /* physical memory backend */ - unsigned int count; - unsigned int allocated; - void *vma; -}; - struct vm_area_struct {}; struct address_space {}; @@ -836,11 +828,6 @@ static inline __must_check long __copy_to_user(void __user *to, case 4: *(u32 __force *)to = *(u32 *)from; return 0; -#ifdef CONFIG_64BIT - case 8: - *(u64 __force *)to = *(u64 *)from; - return 0; -#endif default: break; } @@ -850,6 +837,41 @@ static inline __must_check long __copy_to_user(void __user *to, return 0; } +static __always_inline unsigned long +__copy_from_user(void *to, const void __user *from, unsigned long n) +{ + if (__builtin_constant_p(n)) { + unsigned long ret; + + switch (n) { + case 1: + *(u8 __force *)to = *(u8 *)from; + return 0; + case 2: + *(u16 __force *)to = *(u16 *)from; + return 0; + case 4: + *(u32 __force *)to = *(u32 *)from; + return 0; + default: + break; + } + } + __builtin_memcpy((void __force *)to, from, n); +} + +static inline long copy_from_user(void *to, + const void __user * from, unsigned long n) +{ + return __copy_from_user(to, from, n); +} + +static inline long copy_to_user(void __user *to, + const void *from, unsigned long n) +{ + return __copy_to_user(to, from, n); +} + void *kmap(struct page *page); void *kmap_atomic(struct page *page); void kunmap(struct page *page); diff --git a/drivers/include/linux/workqueue.h b/drivers/include/linux/workqueue.h index 74c4d6858b..fabe30c3a6 100644 --- a/drivers/include/linux/workqueue.h +++ b/drivers/include/linux/workqueue.h @@ -218,6 +218,9 @@ void run_workqueue(struct workqueue_struct *cwq); struct workqueue_struct *alloc_workqueue_key(const char *fmt, unsigned int flags, int max_active); +struct workqueue_struct *alloc_workqueue(const char *fmt, + unsigned int flags, + int max_active); /** * alloc_ordered_workqueue - allocate an ordered workqueue