patch-2.4.22 linux-2.4.22/include/asm-mips/uaccess.h

Next file: linux-2.4.22/include/asm-mips/umap.h
Previous file: linux-2.4.22/include/asm-mips/tx4927/tx4927_pci.h
Back to the patch index
Back to the overall index

diff -urN linux-2.4.21/include/asm-mips/uaccess.h linux-2.4.22/include/asm-mips/uaccess.h
@@ -53,38 +53,131 @@
 
 #define __access_mask ((long)(get_fs().seg))
 
-#define access_ok(type,addr,size) \
-__access_ok(((unsigned long)(addr)),(size),__access_mask)
+/*
+ * access_ok: - Checks if a user space pointer is valid
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE.  Note that
+ *        %VERIFY_WRITE is a superset of %VERIFY_READ - if it is safe
+ *        to write to a block, it is always safe to read from it.
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns true (nonzero) if the memory block may be valid, false (zero)
+ * if it is definitely invalid.
+ *
+ * Note that, depending on architecture, this function probably just
+ * checks that the pointer is in the user space range - after calling
+ * this function, memory access functions may still return -EFAULT.
+ */
+#define access_ok(type, addr, size)					\
+	__access_ok((unsigned long)(addr), (size), __access_mask)
 
+/*
+ * verify_area: - Obsolete, use access_ok()
+ * @type: Type of access: %VERIFY_READ or %VERIFY_WRITE
+ * @addr: User space pointer to start of block to check
+ * @size: Size of block to check
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This function has been replaced by access_ok().
+ *
+ * Checks if a pointer to a block of memory in user space is valid.
+ *
+ * Returns zero if the memory block may be valid, -EFAULT
+ * if it is definitely invalid.
+ *
+ * See access_ok() for more details.
+ */
 static inline int verify_area(int type, const void * addr, unsigned long size)
 {
-	return access_ok(type,addr,size) ? 0 : -EFAULT;
+	return access_ok(type, addr, size) ? 0 : -EFAULT;
 }
 
 /*
- * Uh, these should become the main single-value transfer routines ...
- * They automatically use the right size if we just have the right
- * pointer type ...
- *
- * As MIPS uses the same address space for kernel and user data, we
- * can just do these as direct assignments.
- *
- * Careful to not
- * (a) re-use the arguments for side effects (sizeof is ok)
- * (b) require any knowledge of processes at this stage
+ * put_user: - Write a simple value into user space.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Returns zero on success, or -EFAULT on error.
  */
 #define put_user(x,ptr)	\
 	__put_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+/*
+ * get_user: - Get a simple variable from user space.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
 #define get_user(x,ptr) \
 	__get_user_check((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
 /*
- * The "__xxx" versions do not do address space checking, useful when
- * doing multiple accesses to the same area (the user has to do the
- * checks by hand with "access_ok()")
+ * __put_user: - Write a simple value into user space, with less checking.
+ * @x:   Value to copy to user space.
+ * @ptr: Destination address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple value from kernel space to user
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and @x must be assignable
+ * to the result of dereferencing @ptr.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
  */
 #define __put_user(x,ptr) \
 	__put_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
+
+/*
+ * __get_user: - Get a simple variable from user space, with less checking.
+ * @x:   Variable to store result.
+ * @ptr: Source address, in user space.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * This macro copies a single simple variable from user space to kernel
+ * space.  It supports simple types like char and int, but not larger
+ * data types like structures or arrays.
+ *
+ * @ptr must have pointer-to-simple-variable type, and the result of
+ * dereferencing @ptr must be assignable to @x without a cast.
+ *
+ * Caller must check the pointer with access_ok() before calling this
+ * function.
+ *
+ * Returns zero on success, or -EFAULT on error.
+ * On error, the variable @x is set to zero.
+ */
 #define __get_user(x,ptr) \
 	__get_user_nocheck((__typeof__(*(ptr)))(x),(ptr),sizeof(*(ptr)))
 
@@ -101,76 +194,85 @@
 #define __GET_USER_DW __get_user_asm_ll32
 #endif
 
-#define __get_user_nocheck(x,ptr,size) ({ \
-long __gu_err; \
-__typeof(*(ptr)) __gu_val; \
-long __gu_addr; \
-__asm__("":"=r" (__gu_val)); \
-__gu_addr = (long) (ptr); \
-__asm__("":"=r" (__gu_err)); \
-switch (size) { \
-case 1: __get_user_asm("lb"); break; \
-case 2: __get_user_asm("lh"); break; \
-case 4: __get_user_asm("lw"); break; \
-case 8: __GET_USER_DW; break; \
-default: __get_user_unknown(); break; \
-} x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
-
-#define __get_user_check(x,ptr,size) ({ \
-long __gu_err; \
-__typeof__(*(ptr)) __gu_val; \
-long __gu_addr; \
-__asm__("":"=r" (__gu_val)); \
-__gu_addr = (long) (ptr); \
-__asm__("":"=r" (__gu_err)); \
-if (__access_ok(__gu_addr,size,__access_mask)) { \
-switch (size) { \
-case 1: __get_user_asm("lb"); break; \
-case 2: __get_user_asm("lh"); break; \
-case 4: __get_user_asm("lw"); break; \
-case 8: __GET_USER_DW; break; \
-default: __get_user_unknown(); break; \
-} } x = (__typeof__(*(ptr))) __gu_val; __gu_err; })
-
-#define __get_user_asm(insn) \
-({ \
-__asm__ __volatile__( \
-	"1:\t" insn "\t%1,%2\n\t" \
-	"move\t%0,$0\n" \
-	"2:\n\t" \
-	".section\t.fixup,\"ax\"\n" \
-	"3:\tli\t%0,%3\n\t" \
-	"move\t%1,$0\n\t" \
-	"j\t2b\n\t" \
-	".previous\n\t" \
-	".section\t__ex_table,\"a\"\n\t" \
-	".word\t1b,3b\n\t" \
-	".previous" \
-	:"=r" (__gu_err), "=r" (__gu_val) \
-	:"o" (__m(__gu_addr)), "i" (-EFAULT)); })
+#define __get_user_nocheck(x,ptr,size)				\
+({								\
+	long __gu_err;						\
+	__typeof(*(ptr)) __gu_val;				\
+	long __gu_addr;						\
+	__asm__("":"=r" (__gu_val));				\
+	__gu_addr = (long) (ptr);				\
+	__asm__("":"=r" (__gu_err));				\
+	switch (size) {						\
+		case 1: __get_user_asm("lb"); break;		\
+		case 2: __get_user_asm("lh"); break;		\
+		case 4: __get_user_asm("lw"); break;		\
+		case 8: __GET_USER_DW; break;			\
+		default: __get_user_unknown(); break;		\
+	} x = (__typeof__(*(ptr))) __gu_val;			\
+	__gu_err;						\
+})
+
+#define __get_user_check(x,ptr,size)				\
+({								\
+	long __gu_err;						\
+	__typeof__(*(ptr)) __gu_val;				\
+	long __gu_addr;						\
+	__asm__("":"=r" (__gu_val));				\
+	__gu_addr = (long) (ptr);				\
+	__asm__("":"=r" (__gu_err));				\
+	if (__access_ok(__gu_addr,size,__access_mask)) {	\
+		switch (size) {					\
+		case 1: __get_user_asm("lb"); break;		\
+		case 2: __get_user_asm("lh"); break;		\
+		case 4: __get_user_asm("lw"); break;		\
+		case 8: __GET_USER_DW; break;			\
+		default: __get_user_unknown(); break;		\
+		}						\
+	} x = (__typeof__(*(ptr))) __gu_val;			\
+	__gu_err;						\
+})
+
+#define __get_user_asm(insn)					\
+({								\
+	__asm__ __volatile__(					\
+	"1:\t" insn "\t%1,%2\n\t"				\
+	"move\t%0,$0\n"						\
+	"2:\n\t"						\
+	".section\t.fixup,\"ax\"\n"				\
+	"3:\tli\t%0,%3\n\t"					\
+	"move\t%1,$0\n\t"					\
+	"j\t2b\n\t"						\
+	".previous\n\t"						\
+	".section\t__ex_table,\"a\"\n\t"			\
+	".word\t1b,3b\n\t"					\
+	".previous"						\
+	:"=r" (__gu_err), "=r" (__gu_val)			\
+	:"o" (__m(__gu_addr)), "i" (-EFAULT));			\
+})
 
 /*
  * Get a long long 64 using 32 bit registers.
  */
-#define __get_user_asm_ll32 \
-({ \
-__asm__ __volatile__( \
-	"1:\tlw\t%1,%2\n" \
-	"2:\tlw\t%D1,%3\n\t" \
-	"move\t%0,$0\n" \
-	"3:\t.section\t.fixup,\"ax\"\n" \
-	"4:\tli\t%0,%4\n\t" \
-	"move\t%1,$0\n\t" \
-	"move\t%D1,$0\n\t" \
-	"j\t3b\n\t" \
-	".previous\n\t" \
-	".section\t__ex_table,\"a\"\n\t" \
-	".word\t1b,4b\n\t" \
-	".word\t2b,4b\n\t" \
-	".previous" \
-	:"=r" (__gu_err), "=&r" (__gu_val) \
-	:"o" (__m(__gu_addr)), "o" (__m(__gu_addr + 4)), \
-	 "i" (-EFAULT)); })
+#define __get_user_asm_ll32					\
+({								\
+__asm__ __volatile__(						\
+	"1:\tlw\t%1,%2\n"					\
+	"2:\tlw\t%D1,%3\n\t"					\
+	"move\t%0,$0\n"						\
+	"3:\t.section\t.fixup,\"ax\"\n"				\
+	"4:\tli\t%0,%4\n\t"					\
+	"move\t%1,$0\n\t"					\
+	"move\t%D1,$0\n\t"					\
+	"j\t3b\n\t"						\
+	".previous\n\t"						\
+	".section\t__ex_table,\"a\"\n\t"			\
+	".word\t1b,4b\n\t"					\
+	".word\t2b,4b\n\t"					\
+	".previous"						\
+	:"=r" (__gu_err), "=&r" (__gu_val)			\
+	:"o" (__m(__gu_addr)), "o" (__m(__gu_addr + 4)),	\
+	 "i" (-EFAULT));					\
+})
 
 extern void __get_user_unknown(void);
 
@@ -184,71 +286,80 @@
 #define __PUT_USER_DW __put_user_asm_ll32
 #endif
 
-#define __put_user_nocheck(x,ptr,size) ({ \
-long __pu_err; \
-__typeof__(*(ptr)) __pu_val; \
-long __pu_addr; \
-__pu_val = (x); \
-__pu_addr = (long) (ptr); \
-__asm__("":"=r" (__pu_err)); \
-switch (size) { \
-case 1: __put_user_asm("sb"); break; \
-case 2: __put_user_asm("sh"); break; \
-case 4: __put_user_asm("sw"); break; \
-case 8: __PUT_USER_DW; break; \
-default: __put_user_unknown(); break; \
-} __pu_err; })
-
-#define __put_user_check(x,ptr,size) ({ \
-long __pu_err; \
-__typeof__(*(ptr)) __pu_val; \
-long __pu_addr; \
-__pu_val = (x); \
-__pu_addr = (long) (ptr); \
-__asm__("":"=r" (__pu_err)); \
-if (__access_ok(__pu_addr,size,__access_mask)) { \
-switch (size) { \
-case 1: __put_user_asm("sb"); break; \
-case 2: __put_user_asm("sh"); break; \
-case 4: __put_user_asm("sw"); break; \
-case 8: __PUT_USER_DW; break; \
-default: __put_user_unknown(); break; \
-} } __pu_err; })
-
-#define __put_user_asm(insn) \
-({ \
-__asm__ __volatile__( \
-	"1:\t" insn "\t%z1, %2\t\t\t# __put_user_asm\n\t" \
-	"move\t%0, $0\n" \
-	"2:\n\t" \
-	".section\t.fixup,\"ax\"\n" \
-	"3:\tli\t%0,%3\n\t" \
-	"j\t2b\n\t" \
-	".previous\n\t" \
-	".section\t__ex_table,\"a\"\n\t" \
-	".word\t1b,3b\n\t" \
-	".previous" \
-	:"=r" (__pu_err) \
-	:"Jr" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT)); })
-
-#define __put_user_asm_ll32 \
-({ \
-__asm__ __volatile__( \
-	"1:\tsw\t%1, %2\t\t\t# __put_user_asm_ll32\n\t" \
-	"2:\tsw\t%D1, %3\n" \
-	"move\t%0, $0\n" \
-	"3:\n\t" \
-	".section\t.fixup,\"ax\"\n" \
-	"4:\tli\t%0,%4\n\t" \
-	"j\t3b\n\t" \
-	".previous\n\t" \
-	".section\t__ex_table,\"a\"\n\t" \
-	".word\t1b,4b\n\t" \
-	".word\t2b,4b\n\t" \
-	".previous" \
-	:"=r" (__pu_err) \
+#define __put_user_nocheck(x,ptr,size)				\
+({								\
+	long __pu_err;						\
+	__typeof__(*(ptr)) __pu_val;				\
+	long __pu_addr;						\
+	__pu_val = (x);						\
+	__pu_addr = (long) (ptr);				\
+	__asm__("":"=r" (__pu_err));				\
+	switch (size) {						\
+		case 1: __put_user_asm("sb"); break;		\
+		case 2: __put_user_asm("sh"); break;		\
+		case 4: __put_user_asm("sw"); break;		\
+		case 8: __PUT_USER_DW; break;			\
+		default: __put_user_unknown(); break;		\
+	}							\
+	__pu_err;						\
+})
+
+#define __put_user_check(x,ptr,size)				\
+({								\
+	long __pu_err;						\
+	__typeof__(*(ptr)) __pu_val;				\
+	long __pu_addr;						\
+	__pu_val = (x);						\
+	__pu_addr = (long) (ptr);				\
+	__asm__("":"=r" (__pu_err));				\
+	if (__access_ok(__pu_addr,size,__access_mask)) {	\
+		switch (size) {					\
+		case 1: __put_user_asm("sb"); break;		\
+		case 2: __put_user_asm("sh"); break;		\
+		case 4: __put_user_asm("sw"); break;		\
+		case 8: __PUT_USER_DW; break;			\
+		default: __put_user_unknown(); break;		\
+		}						\
+	}							\
+	__pu_err;						\
+})
+
+#define __put_user_asm(insn)					\
+({								\
+	__asm__ __volatile__(					\
+	"1:\t" insn "\t%z1, %2\t\t\t# __put_user_asm\n\t"	\
+	"move\t%0, $0\n"					\
+	"2:\n\t"						\
+	".section\t.fixup,\"ax\"\n"				\
+	"3:\tli\t%0, %3\n\t"					\
+	"j\t2b\n\t"						\
+	".previous\n\t"						\
+	".section\t__ex_table,\"a\"\n\t"			\
+	".word\t1b, 3b\n\t"					\
+	".previous"						\
+	:"=r" (__pu_err)					\
+	:"Jr" (__pu_val), "o" (__m(__pu_addr)), "i" (-EFAULT));	\
+})
+
+#define __put_user_asm_ll32					\
+({								\
+__asm__ __volatile__(						\
+	"1:\tsw\t%1, %2\t\t\t# __put_user_asm_ll32\n\t"		\
+	"2:\tsw\t%D1, %3\n"					\
+	"move\t%0, $0\n"					\
+	"3:\n\t"						\
+	".section\t.fixup,\"ax\"\n"				\
+	"4:\tli\t%0, %4\n\t"					\
+	"j\t3b\n\t"						\
+	".previous\n\t"						\
+	".section\t__ex_table,\"a\"\n\t"			\
+	".word\t1b,4b\n\t"					\
+	".word\t2b,4b\n\t"					\
+	".previous"						\
+	:"=r" (__pu_err)					\
 	:"r" (__pu_val), "o" (__m(__pu_addr)), "o" (__m(__pu_addr + 4)), \
-	 "i" (-EFAULT)); })
+	 "i" (-EFAULT));					\
+})
 
 extern void __put_user_unknown(void);
 
@@ -257,19 +368,20 @@
  * jump instructions
  */
 #ifdef MODULE
-#define __MODULE_JAL(destination) \
-	".set\tnoat\n\t" \
-	"la\t$1, " #destination "\n\t" \
-	"jalr\t$1\n\t" \
+#define __MODULE_JAL(destination)	\
+	".set\tnoat\n\t"		\
+	"la\t$1, " #destination "\n\t"	\
+	"jalr\t$1\n\t"			\
 	".set\tat\n\t"
 #else
-#define __MODULE_JAL(destination) \
+#define __MODULE_JAL(destination)	\
 	"jal\t" #destination "\n\t"
 #endif
 
 extern size_t __copy_user(void *__to, const void *__from, size_t __n);
 
-#define __invoke_copy_to_user(to,from,n) ({				\
+#define __invoke_copy_to_user(to,from,n)				\
+({									\
 	register void *__cu_to_r __asm__ ("$4");			\
 	register const void *__cu_from_r __asm__ ("$5");		\
 	register long __cu_len_r __asm__ ("$6");			\
@@ -278,7 +390,7 @@
 	__cu_from_r = (from);						\
 	__cu_len_r = (n);						\
 	__asm__ __volatile__(						\
-		__MODULE_JAL(__copy_user)				\
+	__MODULE_JAL(__copy_user)					\
 	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
 	:								\
 	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
@@ -286,7 +398,22 @@
 	__cu_len_r;							\
 })
 
-#define __copy_to_user(to,from,n) ({					\
+/*
+ * __copy_to_user: - Copy a block of data into user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+#define __copy_to_user(to,from,n)					\
+({									\
 	void *__cu_to;							\
 	const void *__cu_from;						\
 	long __cu_len;							\
@@ -298,7 +425,21 @@
 	__cu_len;							\
 })
 
-#define copy_to_user(to,from,n) ({					\
+/*
+ * copy_to_user: - Copy a block of data into user space.
+ * @to:   Destination address, in user space.
+ * @from: Source address, in kernel space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from kernel space to user space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ */
+#define copy_to_user(to,from,n)						\
+({									\
 	void *__cu_to;							\
 	const void *__cu_from;						\
 	long __cu_len;							\
@@ -312,7 +453,8 @@
 	__cu_len;							\
 })
 
-#define __invoke_copy_from_user(to,from,n) ({				\
+#define __invoke_copy_from_user(to,from,n)				\
+({									\
 	register void *__cu_to_r __asm__ ("$4");			\
 	register const void *__cu_from_r __asm__ ("$5");		\
 	register long __cu_len_r __asm__ ("$6");			\
@@ -321,12 +463,12 @@
 	__cu_from_r = (from);						\
 	__cu_len_r = (n);						\
 	__asm__ __volatile__(						\
-		".set\tnoreorder\n\t"					\
-		__MODULE_JAL(__copy_user)				\
-		".set\tnoat\n\t"					\
-		"addu\t$1, %1, %2\n\t"					\
-		".set\tat\n\t"						\
-		".set\treorder\n\t"					\
+	".set\tnoreorder\n\t"						\
+	__MODULE_JAL(__copy_user)					\
+	".set\tnoat\n\t"						\
+	"addu\t$1, %1, %2\n\t"						\
+	".set\tat\n\t"							\
+	".set\treorder\n\t"						\
 	: "+r" (__cu_to_r), "+r" (__cu_from_r), "+r" (__cu_len_r)	\
 	:								\
 	: "$8", "$9", "$10", "$11", "$12", "$15", "$24", "$31",		\
@@ -334,7 +476,24 @@
 	__cu_len_r;							\
 })
 
-#define __copy_from_user(to,from,n) ({					\
+/*
+ * __copy_from_user: - Copy a block of data from user space, with less checking. * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+#define __copy_from_user(to,from,n)					\
+({									\
 	void *__cu_to;							\
 	const void *__cu_from;						\
 	long __cu_len;							\
@@ -347,7 +506,24 @@
 	__cu_len;							\
 })
 
-#define copy_from_user(to,from,n) ({					\
+/*
+ * copy_from_user: - Copy a block of data from user space.
+ * @to:   Destination address, in kernel space.
+ * @from: Source address, in user space.
+ * @n:    Number of bytes to copy.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Copy data from user space to kernel space.
+ *
+ * Returns number of bytes that could not be copied.
+ * On success, this will be zero.
+ *
+ * If some data could not be copied, this function will pad the copied
+ * data to the requested size using zero bytes.
+ */
+#define copy_from_user(to,from,n)					\
+({									\
 	void *__cu_to;							\
 	const void *__cu_from;						\
 	long __cu_len;							\
@@ -361,6 +537,17 @@
 	__cu_len;							\
 })
 
+/*
+ * __clear_user: - Zero a block of memory in user space, with less checking.
+ * @to:   Destination address, in user space.
+ * @n:    Number of bytes to zero.
+ *
+ * Zero a block of memory in user space.  Caller must check
+ * the specified block with access_ok() before calling this function.
+ *
+ * Returns number of bytes that could not be cleared.
+ * On success, this will be zero.
+ */
 static inline __kernel_size_t
 __clear_user(void *addr, __kernel_size_t size)
 {
@@ -379,16 +566,35 @@
 	return res;
 }
 
-#define clear_user(addr,n) ({ \
-void * __cl_addr = (addr); \
-unsigned long __cl_size = (n); \
-if (__cl_size && access_ok(VERIFY_WRITE, ((unsigned long)(__cl_addr)), __cl_size)) \
-__cl_size = __clear_user(__cl_addr, __cl_size); \
-__cl_size; })
+#define clear_user(addr,n)					\
+({								\
+	void * __cl_addr = (addr);				\
+	unsigned long __cl_size = (n);				\
+	if (__cl_size && access_ok(VERIFY_WRITE,		\
+		((unsigned long)(__cl_addr)), __cl_size))	\
+		__cl_size = __clear_user(__cl_addr, __cl_size);	\
+	__cl_size;						\
+})
 
 /*
- * Returns: -EFAULT if exception before terminator, N if the entire
- * buffer filled, else strlen.
+ * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from userspace to kernel space.
+ * Caller must check the specified block with access_ok() before calling
+ * this function.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
  */
 static inline long
 __strncpy_from_user(char *__to, const char *__from, long __len)
@@ -408,6 +614,24 @@
 	return res;
 }
 
+/*
+ * strncpy_from_user: - Copy a NUL terminated string from userspace.
+ * @dst:   Destination address, in kernel space.  This buffer must be at
+ *         least @count bytes long.
+ * @src:   Source address, in user space.
+ * @count: Maximum number of bytes to copy, including the trailing NUL.
+ *
+ * Copies a NUL-terminated string from userspace to kernel space.
+ *
+ * On success, returns the length of the string (not including the trailing
+ * NUL).
+ *
+ * If access to userspace fails, returns -EFAULT (some data may have been
+ * copied).
+ *
+ * If @count is smaller than the length of the string, copies @count bytes
+ * and returns @count.
+ */
 static inline long
 strncpy_from_user(char *__to, const char *__from, long __len)
 {
@@ -442,6 +666,20 @@
 	return res;
 }
 
+/*
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ *
+ * Context: User context only.  This function may sleep.
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ *
+ * If there is a limit on the length of a valid string, you may wish to
+ * consider using strnlen_user() instead.
+ */
 static inline long strlen_user(const char *s)
 {
 	long res;
@@ -457,23 +695,17 @@
 	return res;
 }
 
-/* Returns: 0 if bad, string length+1 (memory size) of string if ok */
-static inline long __strnlen_user(const char *s, long n)
-{
-	long res;
-
-	__asm__ __volatile__(
-		"move\t$4, %1\n\t"
-		"move\t$5, %2\n\t"
-		__MODULE_JAL(__strnlen_user_nocheck_asm)
-		"move\t%0, $2"
-		: "=r" (res)
-		: "r" (s), "r" (n)
-		: "$2", "$4", "$5", "$8", "$31");
-
-	return res;
-}
-
+/*
+ * strlen_user: - Get the size of a string in user space.
+ * @str: The string to measure.
+ * @n:   The maximum valid length
+ *
+ * Get the size of a NUL-terminated string in user space.
+ *
+ * Returns the size of the string INCLUDING the terminating NUL.
+ * On exception, returns 0.
+ * If the string is too long, returns a value greater than @n.
+ */
 static inline long strnlen_user(const char *s, long n)
 {
 	long res;

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)