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
- Lines: 752
- Date:
2003-08-25 04:44:44.000000000 -0700
- Orig file:
linux-2.4.21/include/asm-mips/uaccess.h
- Orig date:
2002-08-02 17:39:45.000000000 -0700
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)