Linux 3.8: session_keyring changes
[openafs.git] / src / afs / LINUX / osi_compat.h
1 /* Kernel compatibility routines
2  *
3  * This file contains definitions to provide compatibility between different
4  * versions of the Linux kernel. It is an ifdef maze, but the idea is that
5  * by concentrating the horror here, the rest of the tree may remaing a
6  * little cleaner...
7  */
8
9 #ifndef AFS_LINUX_OSI_COMPAT_H
10 #define AFS_LINUX_OSI_COMPAT_H
11
12 #if defined(HAVE_LINUX_FREEZER_H)
13 # include <linux/freezer.h>
14 #endif
15
16 #if defined(LINUX_KEYRING_SUPPORT)
17 # include <linux/rwsem.h>
18 # include <linux/key.h>
19 # if defined(HAVE_LINUX_KEY_TYPE_H)
20 #  include <linux/key-type.h>
21 # endif
22 # ifndef KEY_ALLOC_IN_QUOTA
23 /* Before these flags were added in Linux commit v2.6.18-rc1~816,
24  * key_alloc just took a boolean not_in_quota */
25 #  define KEY_ALLOC_IN_QUOTA 0
26 #  define KEY_ALLOC_NOT_IN_QUOTA 1
27 # endif
28 #endif
29
30 #if defined(STRUCT_DENTRY_OPERATIONS_HAS_D_AUTOMOUNT) && !defined(DCACHE_NEED_AUTOMOUNT)
31 # define DCACHE_NEED_AUTOMOUNT DMANAGED_AUTOMOUNT
32 #endif
33
34 #ifdef HAVE_LINUX_STRUCT_VFS_PATH
35 typedef struct vfs_path afs_linux_path_t;
36 #else
37 typedef struct path afs_linux_path_t;
38 #endif
39
40 #ifndef HAVE_LINUX_DO_SYNC_READ
41 static inline int
42 do_sync_read(struct file *fp, char *buf, size_t count, loff_t *offp) {
43     return generic_file_read(fp, buf, count, offp);
44 }
45
46 static inline int
47 do_sync_write(struct file *fp, char *buf, size_t count, loff_t *offp) {
48     return generic_file_write(fp, buf, count, offp);
49 }
50
51 #endif /* DO_SYNC_READ */
52
53 static inline int
54 afs_posix_lock_file(struct file *fp, struct file_lock *flp) {
55 #ifdef POSIX_LOCK_FILE_WAIT_ARG
56     return posix_lock_file(fp, flp, NULL);
57 #else
58     flp->fl_flags &=~ FL_SLEEP;
59     return posix_lock_file(fp, flp);
60 #endif
61 }
62
63 static inline void
64 afs_posix_test_lock(struct file *fp, struct file_lock *flp) {
65 #if defined(POSIX_TEST_LOCK_CONFLICT_ARG)
66     struct file_lock conflict;
67     if (posix_test_lock(fp, flp, &conflict)) {
68         locks_copy_lock(flp, &conflict);
69         flp->fl_type = F_UNLCK;
70     }
71 #elif defined(POSIX_TEST_LOCK_RETURNS_CONFLICT)
72     struct file_lock *conflict;
73     conflict = posix_test_lock(fp, flp);
74     if (conflict) {
75         locks_copy_lock(flp, conflict);
76         flp->fl_type = F_UNLCK;
77     }
78 #else
79     posix_test_lock(fp, flp);
80 #endif
81 }
82
83 #ifdef DCACHE_NFSFS_RENAMED
84 static inline void
85 afs_linux_clear_nfsfs_renamed(struct dentry *dp) {
86     spin_lock(&dp->d_lock);
87     dp->d_flags &= ~DCACHE_NFSFS_RENAMED;
88     spin_unlock(&dp->d_lock);
89 }
90
91 static inline void
92 afs_linux_set_nfsfs_renamed(struct dentry *dp) {
93     spin_lock(&dp->d_lock);
94     dp->d_flags |= DCACHE_NFSFS_RENAMED;
95     spin_unlock(&dp->d_lock);
96 }
97
98 static inline int
99 afs_linux_nfsfs_renamed(struct dentry *dp) {
100     return dp->d_flags & DCACHE_NFSFS_RENAMED;
101 }
102
103 #else
104 static inline void afs_linux_clear_nfsfs_renamed(void) { return; }
105 static inline void afs_linux_set_nfsfs_renamed(void) { return; }
106 #endif
107
108 #ifndef HAVE_LINUX_HLIST_UNHASHED
109 static void
110 hlist_unhashed(const struct hlist_node *h) {
111     return (!h->pprev == NULL);
112 }
113 #endif
114
115 #if defined(WRITEPAGE_ACTIVATE)
116 #define AOP_WRITEPAGE_ACTIVATE WRITEPAGE_ACTIVATE
117 #endif
118
119 #if defined(STRUCT_ADDRESS_SPACE_OPERATIONS_HAS_WRITE_BEGIN) && !defined(HAVE_LINUX_GRAB_CACHE_PAGE_WRITE_BEGIN)
120 static inline struct page *
121 grab_cache_page_write_begin(struct address_space *mapping, pgoff_t index,
122                             unsigned int flags) {
123     return __grab_cache_page(mapping, index);
124 }
125 #endif
126
127 #if defined(HAVE_KMEM_CACHE_T)
128 #define afs_kmem_cache_t kmem_cache_t
129 #else
130 #define afs_kmem_cache_t struct kmem_cache
131 #endif
132
133 extern void init_once(void *);
134 #if defined(HAVE_KMEM_CACHE_T)
135 static inline void
136 init_once_func(void * foo, kmem_cache_t * cachep, unsigned long flags) {
137 #if defined(SLAB_CTOR_VERIFY)
138     if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
139         SLAB_CTOR_CONSTRUCTOR)
140 #endif
141     init_once(foo);
142 }
143 #elif defined(KMEM_CACHE_INIT)
144 static inline void
145 init_once_func(struct kmem_cache * cachep, void * foo) {
146     init_once(foo);
147 }
148 #elif !defined(KMEM_CACHE_CTOR_TAKES_VOID)
149 static inline void
150 init_once_func(void * foo, struct kmem_cache * cachep, unsigned long flags) {
151 #if defined(SLAB_CTOR_VERIFY)
152     if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) ==
153         SLAB_CTOR_CONSTRUCTOR)
154 #endif
155     init_once(foo);
156 }
157 #else
158 static inline void
159 init_once_func(void * foo) {
160     init_once(foo);
161 }
162 #endif
163
164 #ifndef SLAB_RECLAIM_ACCOUNT
165 #define SLAB_RECLAIM_ACCOUNT 0
166 #endif
167
168 #if defined(SLAB_KERNEL)
169 #define KALLOC_TYPE SLAB_KERNEL
170 #else
171 #define KALLOC_TYPE GFP_KERNEL
172 #endif
173
174 #ifdef LINUX_KEYRING_SUPPORT
175 static inline struct key *
176 afs_linux_key_alloc(struct key_type *type, const char *desc, uid_t uid,
177                     gid_t gid, key_perm_t perm, unsigned long flags)
178 {
179 # if defined(KEY_ALLOC_NEEDS_STRUCT_TASK)
180     return key_alloc(type, desc, uid, gid, current, perm, flags);
181 # elif defined(KEY_ALLOC_NEEDS_CRED)
182     return key_alloc(type, desc, uid, gid, current_cred(), perm, flags);
183 # else
184     return key_alloc(type, desc, uid, gid, perm, flags);
185 # endif
186 }
187
188 # if defined(STRUCT_TASK_STRUCT_HAS_CRED)
189 static inline struct key *
190 afs_session_keyring(afs_ucred_t *cred)
191 {
192 #  if defined(STRUCT_CRED_HAS_SESSION_KEYRING)
193     return cred->session_keyring;
194 #  else
195     return cred->tgcred->session_keyring;
196 #  endif
197 }
198
199 static inline struct key*
200 afs_linux_search_keyring(afs_ucred_t *cred, struct key_type *type)
201 {
202     key_ref_t key_ref;
203
204     if (afs_session_keyring(cred)) {
205         key_ref = keyring_search(
206                       make_key_ref(afs_session_keyring(cred), 1),
207                       type, "_pag");
208         if (IS_ERR(key_ref))
209             return ERR_CAST(key_ref);
210
211         return key_ref_to_ptr(key_ref);
212     }
213
214     return ERR_PTR(-ENOKEY);
215 }
216 # else
217 static inline struct key*
218 afs_linux_search_keyring(afs_ucred_t *cred, struct key_type *type)
219 {
220     return request_key(type, "_pag", NULL);
221 }
222 # endif /* STRUCT_TASK_STRUCT_HAS_CRED */
223 #endif /* LINUX_KEYRING_SUPPORT */
224
225 #ifdef STRUCT_TASK_STRUCT_HAS_CRED
226 static inline int
227 afs_linux_cred_is_current(afs_ucred_t *cred)
228 {
229     return (cred == current_cred());
230 }
231 #else
232 static inline int
233 afs_linux_cred_is_current(afs_ucred_t *cred)
234 {
235     return 1;
236 }
237 #endif
238
239 #ifndef HAVE_LINUX_PAGE_OFFSET
240 static inline loff_t
241 page_offset(struct page *pp)
242 {
243     return (((loff_t) pp->index) << PAGE_CACHE_SHIFT);
244 }
245 #endif
246
247 #ifndef HAVE_LINUX_ZERO_USER_SEGMENTS
248 static inline void
249 zero_user_segments(struct page *pp, unsigned int from1, unsigned int to1,
250                    unsigned int from2, unsigned int to2)
251 {
252     void *base = kmap_atomic(pp, KM_USER0);
253
254     if (to1 > from1)
255         memset(base + from1, 0, to1 - from1);
256
257     if (to2 > from2)
258         memset(base + from2, 0, to2 - from2);
259
260     flush_dcache_page(pp);
261     kunmap_atomic(base, KM_USER0);
262 }
263
264 static inline void
265 zero_user_segment(struct page *pp, unsigned int from1, unsigned int to1)
266 {
267     zero_user_segments(pp, from1, to1, 0, 0);
268 }
269 #endif
270
271 #ifndef HAVE_LINUX_KERNEL_SETSOCKOPT
272 /* Available from 2.6.19 */
273
274 static inline int
275 kernel_setsockopt(struct socket *sockp, int level, int name, char *val,
276                   unsigned int len) {
277     mm_segment_t old_fs = get_fs();
278     int ret;
279
280     set_fs(get_ds());
281     ret = sockp->ops->setsockopt(sockp, level, name, val, len);
282     set_fs(old_fs);
283
284     return ret;
285 }
286
287 static inline int
288 kernel_getsockopt(struct socket *sockp, int level, int name, char *val,
289                   int *len) {
290     mm_segment_t old_fs = get_fs();
291     int ret;
292
293     set_fs(get_ds());
294     ret = sockp->ops->getsockopt(sockp, level, name, val, len);
295     set_fs(old_fs);
296
297     return ret;
298 }
299 #endif
300
301 #ifdef HAVE_TRY_TO_FREEZE
302 static inline int
303 afs_try_to_freeze(void) {
304 # ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
305     return try_to_freeze(PF_FREEZE);
306 # else
307     return try_to_freeze();
308 # endif
309 }
310 #else
311 static inline int
312 afs_try_to_freeze(void) {
313 # ifdef CONFIG_PM
314     if (current->flags & PF_FREEZE) {
315         refrigerator(PF_FREEZE);
316         return 1;
317     }
318 # endif
319     return 0;
320 }
321 #endif
322
323 /* The commit which changed refrigerator so that it takes no arguments
324  * also added freezing(), so if LINUX_REFRIGERATOR_TAKES_PF_FREEZE is
325  * true, the kernel doesn't have a freezing() function.
326  */
327 #ifdef LINUX_REFRIGERATOR_TAKES_PF_FREEZE
328 static inline int
329 freezing(struct task_struct *p)
330 {
331 # ifdef CONFIG_PM
332     return p->flags & PF_FREEZE;
333 # else
334     return 0;
335 # endif
336 }
337 #endif
338
339 #if !defined(HAVE_LINUX_PAGECHECKED)
340 # if defined(HAVE_LINUX_PAGEFSMISC)
341 #  include <linux/page-flags.h>
342
343 #  define PageChecked(p)            PageFsMisc((p))
344 #  define SetPageChecked(p)         SetPageFsMisc((p))
345 #  define ClearPageChecked(p)       ClearPageFsMisc((p))
346
347 # endif
348 #endif
349
350 #if !defined(NEW_EXPORT_OPS)
351 extern struct export_operations export_op_default;
352 #endif
353
354 static inline struct dentry *
355 afs_get_dentry_from_fh(struct super_block *afs_cacheSBp, afs_dcache_id_t *ainode,
356                 int cache_fh_len, int cache_fh_type,
357                 int (*afs_fh_acceptable)(void *, struct dentry *)) {
358 #if defined(NEW_EXPORT_OPS)
359     return afs_cacheSBp->s_export_op->fh_to_dentry(afs_cacheSBp, &ainode->ufs.fh,
360                 cache_fh_len, cache_fh_type);
361 #else
362     if (afs_cacheSBp->s_export_op && afs_cacheSBp->s_export_op->decode_fh)
363         return afs_cacheSBp->s_export_op->decode_fh(afs_cacheSBp, ainode->ufs.raw,
364                         cache_fh_len, cache_fh_type, afs_fh_acceptable, NULL);
365     else
366         return export_op_default.decode_fh(afs_cacheSBp, ainode->ufs.raw,
367                         cache_fh_len, cache_fh_type, afs_fh_acceptable, NULL);
368 #endif
369 }
370
371 static inline int
372 afs_get_fh_from_dentry(struct dentry *dp, afs_ufs_dcache_id_t *ainode, int *max_lenp) {
373     if (dp->d_sb->s_export_op->encode_fh)
374 #if defined(EXPORT_OP_ENCODE_FH_TAKES_INODES)
375         return dp->d_sb->s_export_op->encode_fh(dp->d_inode, &ainode->raw[0], max_lenp, NULL);
376 #else
377         return dp->d_sb->s_export_op->encode_fh(dp, &ainode->raw[0], max_lenp, 0);
378 #endif
379 #if defined(NEW_EXPORT_OPS)
380     /* If fs doesn't provide an encode_fh method, assume the default INO32 type */
381     *max_lenp = sizeof(struct fid)/4;
382     ainode->fh.i32.ino = dp->d_inode->i_ino;
383     ainode->fh.i32.gen = dp->d_inode->i_generation;
384     return FILEID_INO32_GEN;
385 #else
386     /* or call the default encoding function for the old API */
387     return export_op_default.encode_fh(dp, &ainode->raw[0], max_lenp, 0);
388 #endif
389 }
390
391 static inline void
392 afs_init_sb_export_ops(struct super_block *sb) {
393 #if !defined(NEW_EXPORT_OPS)
394     /*
395      * decode_fh will call this function.  If not defined for this FS, make
396      * sure it points to the default
397      */
398     if (!sb->s_export_op->find_exported_dentry) {
399         /* Some kernels (at least 2.6.9) do not prototype find_exported_dentry,
400          * even though it is exported, so prototype it ourselves. Newer
401          * kernels do prototype it, but as long as our protoype matches the
402          * real one (the signature never changed before NEW_EXPORT_OPS came
403          * into play), there should be no problems. */
404         extern struct dentry * find_exported_dentry(struct super_block *sb, void *obj, void *parent,
405                                                     int (*acceptable)(void *context, struct dentry *de),
406                                                     void *context);
407         sb->s_export_op->find_exported_dentry = find_exported_dentry;
408     }
409 #endif
410 }
411
412 static inline void
413 afs_linux_lock_inode(struct inode *ip) {
414 #ifdef STRUCT_INODE_HAS_I_MUTEX
415     mutex_lock(&ip->i_mutex);
416 #else
417     down(&ip->i_sem);
418 #endif
419 }
420
421 static inline void
422 afs_linux_unlock_inode(struct inode *ip) {
423 #ifdef STRUCT_INODE_HAS_I_MUTEX
424     mutex_unlock(&ip->i_mutex);
425 #else
426     up(&ip->i_sem);
427 #endif
428 }
429
430 static inline int
431 afs_inode_setattr(struct osi_file *afile, struct iattr *newattrs) {
432
433     int code = 0;
434     struct inode *inode = OSIFILE_INODE(afile);
435 #if !defined(HAVE_LINUX_INODE_SETATTR)
436     code = inode->i_op->setattr(afile->filp->f_dentry, newattrs);
437 #elif defined(INODE_SETATTR_NOT_VOID)
438     if (inode->i_op && inode->i_op->setattr)
439         code = inode->i_op->setattr(afile->filp->f_dentry, newattrs);
440     else
441         code = inode_setattr(inode, newattrs);
442 #else
443     inode_setattr(inode, newattrs);
444 #endif
445     return code;
446 }
447
448 #if defined(HAVE_LINUX_PATH_LOOKUP)
449 static inline int
450 afs_kern_path(char *aname, int flags, struct nameidata *nd) {
451     return path_lookup(aname, flags, nd);
452 }
453 #else
454 static inline int
455 afs_kern_path(char *aname, int flags, afs_linux_path_t *path) {
456     return kern_path(aname, flags, path);
457 }
458 #endif
459
460 static inline void
461 #if defined(HAVE_LINUX_PATH_LOOKUP)
462 afs_get_dentry_ref(struct nameidata *nd, struct vfsmount **mnt, struct dentry **dpp) {
463 #else
464 afs_get_dentry_ref(afs_linux_path_t *path, struct vfsmount **mnt, struct dentry **dpp) {
465 #endif
466 #if defined(STRUCT_NAMEIDATA_HAS_PATH)
467 # if defined(HAVE_LINUX_PATH_LOOKUP)
468     *dpp = dget(nd->path.dentry);
469     if (mnt)
470         *mnt = mntget(nd->path.mnt);
471     path_put(&nd->path);
472 # else
473     *dpp = dget(path->dentry);
474     if (mnt)
475         *mnt = mntget(path->mnt);
476     path_put(path);
477 # endif
478 #else
479     *dpp = dget(nd->dentry);
480     if (mnt)
481         *mnt = mntget(nd->mnt);
482     path_release(nd);
483 #endif
484 }
485
486 /* wait_event_freezable appeared with 2.6.24 */
487
488 /* These implement the original AFS wait behaviour, with respect to the
489  * refrigerator, rather than the behaviour of the current wait_event_freezable
490  * implementation.
491  */
492
493 #ifndef wait_event_freezable
494 # define wait_event_freezable(waitqueue, condition)                             \
495 ({                                                                              \
496     int _ret;                                                                   \
497     do {                                                                        \
498         _ret = wait_event_interruptible(waitqueue,                              \
499                                         (condition) || freezing(current));      \
500         if (_ret && !freezing(current))                                 \
501             break;                                                              \
502         else if (!(condition))                                                  \
503             _ret = -EINTR;                                                      \
504     } while (afs_try_to_freeze());                                              \
505     _ret;                                                                       \
506 })
507
508 # define wait_event_freezable_timeout(waitqueue, condition, timeout)            \
509 ({                                                                              \
510      int _ret;                                                                  \
511      do {                                                                       \
512         _ret = wait_event_interruptible_timeout(waitqueue,                      \
513                                                 (condition ||                   \
514                                                  freezing(current)),            \
515                                                 timeout);                       \
516      } while (afs_try_to_freeze());                                             \
517      _ret;                                                                      \
518 })
519 #endif
520
521 #if defined(STRUCT_TASK_STRUCT_HAS_CRED)
522 static inline struct file *
523 afs_dentry_open(struct dentry *dp, struct vfsmount *mnt, int flags, const struct cred *creds) {
524 #if defined(DENTRY_OPEN_TAKES_PATH)
525     afs_linux_path_t path;
526     struct file *filp;
527     path.mnt = mnt;
528     path.dentry = dp;
529     filp = dentry_open(&path, flags, creds);
530     return filp;
531 #else
532     return dentry_open(dp, mntget(mnt), flags, creds);
533 #endif
534 }
535 #endif
536
537 #if !defined(STRUCT_FILENAME_HAS_NAME)
538 typedef char *afs_name_t;
539
540 static inline char *
541 afs_name_to_string(afs_name_t s) {
542     return (char *)s;
543 }
544
545 static inline void
546 afs_putname(afs_name_t name) {
547     putname((char *)name);
548 }
549 #else
550 typedef struct filename *afs_name_t;
551
552 static inline char *
553 afs_name_to_string(afs_name_t s) {
554     return (char *)s->name;
555 }
556
557 static inline void
558 afs_putname(afs_name_t name) {
559     kmem_cache_free(names_cachep, (void *)name);
560 }
561 #endif
562
563 static_inline struct key *
564 afs_set_session_keyring(struct key *keyring)
565 {
566     struct key *old;
567 #if defined(STRUCT_CRED_HAS_SESSION_KEYRING)
568     struct cred *new_creds;
569     old = current_session_keyring();
570     new_creds = prepare_creds();
571     rcu_assign_pointer(new_creds->session_keyring, keyring);
572     commit_creds(new_creds);
573 #else
574     spin_lock_irq(&current->sighand->siglock);
575     old = task_session_keyring(current);
576     smp_wmb();
577     task_session_keyring(current) = keyring;
578     spin_unlock_irq(&current->sighand->siglock);
579 #endif
580     return old;
581 }
582
583 #endif /* AFS_LINUX_OSI_COMPAT_H */